const
const 修饰的是只读变量,不是常量,会在内存中占用空间,本质上const只对编译器有用,在运行时无用
const 修饰的只读变量不能作为左值直接赋值,但可以通知指针修改其值
const 修饰的只读变量必须在定义的同时初始化
case语句后面不可以跟const修饰的只读变量,case后面只能是整形或者字符型的常量或常量表达式
const修饰的数组是只读的,const修饰的数组空间不可以被改变
const int c = 1;
int* p = (int*)&c;
//c = 2;会报错
printf("%dn",c);//输出1
*p = 2;
printf("%dn",c);//输出2
const int* p;
int const* p;
int* const p;
const int* const p;
口诀:左数右指
当const出现在*左边时指针指向的数据为常量不可改变
当const出现在*右边时指针本事为常量不可改变
const在*两边时指p和p指向的内容都不可改变
const修饰函数参数表示在函数体内不希望改变参数的值
const修饰函数返回值表示返回值不可改变,多用于返回指针的情形
volatile
可理解为“编译器警告指示字”
用于告诉编译器必须每次去内存中取变量值
主要修饰可能被多个线程访问的变量
也可修饰可能被未知因数更改的变量
volatile 关键字和const 一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
例子:
int i=10;
int j = i ;//(1)语句
int k = i ;//(2)语句
这时候编译器对代码进行优化,因为在(1)、(2)两条语句中,i没有被用作左值。这时候编译器认为i的值没有发生改变,所以在(1)语句时从内存中取出i的值赋给j之后,这个值并没有被丢掉,而是在(2)语句时继续用这个值给k 赋值。编译器不会生成出汇编代码重新从内存里取i的值,这样提高了效率。但要注意(1)、(2)语句之间i没有被用作左值才行。
另一个例子:
volatile int i=10;
int j = i ;//(3)语句
int k = i ;//(4)语句
volatile关键字告诉编译器i是随时可能发生变化的,每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k 中。这样看来,如果i是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说volatile可以保证对特殊地址的稳定访问。
volatile const int i; const和volatile可以同时使用。例如,硬件时钟一般设定为不能由程序改变,这一点使它成为const;但它被程序以外的代理改变,这使它成为volatile的。volatile和const并不矛盾,只是控制的范围不一样,一个在程序本身之外,另一个是程序本身。