1. const
变量声明中带有关键词const,意味着不能通过赋值,增量或减量来修改该变量的值,这是显而易见的一点。指针使用const则要稍微复杂点,因为不得不把让指针本身成为const和指针指向的值成为const区别开来、下面的声明表示pf指向的值必须是不变的
constfloat *pf;而pf则是可变的,它可以指向另外一个const或非const值;相反,下面的声明说明pf是不能改变的,而pf所指向的值则是可以改变的:
float* const pf;
最后,当然可以有既不能改变指针的值也不能改变指针指向的值的值的声明方式:
constfloat * const pf;
需要注意的是,还有第三种放置const关键字的方法:
float const * pf; //等价于constfloat * pf;
总结就是:一个位于*左边任意位置的const使得数据成为常量,而一个位于*右边的const使得指针本身成为const
还要注意的一点是关于const在全局数据中的使用:
使用全局变量被认为是一个冒险的方法,它使得数据在程序的任何部分都可以被错误地修改,如果数据是const,那么这种担心就是多余的了不是嘛?因此对全局数据使用const是合理的。
然而,在文件之间共享const数据要格外小心,有两个策略可以使用。一个是遵循外部变量的惯用规则,在一个文件进行定义声明,在其他文件进行引用声明(使用关键字extern)。
/*file1.c------定义一些全局常量*/
const double PI = 3.14159;
/*file2.c-----是用在其他文件中定义的全局变量*/
extern const dounle PI;
另外一个方法是把全局变量放在一个include文件里,这时候需要格外注意的是必须使用静态外部存储类
/*constant.h----定义一些全局常量*/
static const double PI = 3.14159;
/*file1.c-----使用其他文件定义的全局变量*/
#include”constant.h”。
/*file2.c-----使用其他文件定义的全局变量*/
#include”constant.h”
如果不使用关键字static,在文件file1.c和file2.c中包含constant.h将导致每个文件都有同一标识符的定义声明ANSI标准不支持这样做(有些编译器确实支持)。通过使用static, 实际上给了每个文件一个独立的数据拷贝,如果文件想使用该数据与另外一个文件通话,这样做就不行了,因为每个文件只能看见他自己的拷贝,然而由于数据是不 可变的,这就不是问题了。使用头文件的好处是不必惦记在一个文件中进行定义声明,在另一个文件中进行引用声明,缺点在于复制了数据,如果常量很大的话,这 就是个问题了。
2. volatile
限定词volatile告诉编译器,该变量除了可被程序改变意外还可以被其他代理改变。典型的它用于硬件地址和其他并行运行的程序共享的数据。例如,一个地址中可能保存着当前的时钟信息。不管程序做些什么,该地址会随时间改变。另一种情况是一个地址用来接收来自其他计算机的信息;
语法同const:
volatile int a;//a是一个易变的位置
volatile int * pf;//pf指向一个易变的位置
把volatile作为一个关键字的原因是它可以方便编译器优化。
假如有如下代码:
va= x;
//一些不使用x的代码
vb= x;
一个聪明的编译器可能注意到你两次使用了x,但是没有改变它的值,它将把x临时存贮在一个寄存器中,接着,当vb主要x是的时候,它从寄存器而非初始的内存位置得到x的值来节省时间。这个过程被称为缓存。通常缓存是一个好的优化方式,但是如果两个语句中间的其他代理改变了x的值的话就不是这样了。如果没有规定volatile关键字,编译器将无从得知这种改变是否可能发生,因此,为了安全起见,编译器不使用缓存。那是在ANSI以前的情形,现在,如果在声明中没有使用volatile关键字,编译器就可以假定一个值在使用过程中没有修改,它就可以试着优化代码。总而言之,volatile使得每次读取数据都是直接在内存读取而不是缓存。
你可能会觉得奇怪,const和volatile可以同时使用,但是确实可以。例如硬件时钟一般不能由程序改变,这使得他成为const,但他被程序以外的代理改变,这使得他成为volatile,所以你可以同时使用它们,顺序是不重要的:
const volatile time;