C语言进阶:const和volatile
const只读变量。
const修饰的变量是可读的,本质上是变量。
const修饰的局部变量在栈上分配空间;
const修饰的全局变量在全局数据区分配空间;
const只在编译期有用,在运行期无用。
所以,本质上来讲,const修饰的其实不是常量,而是一个不能被改变的变量(不能出现在赋值符号的左边)。
在现代编译器中,修改const全局变量将导致程序崩溃。
注意:标准c语言编译器不会将const修饰的全局变量存储于只读存储区,而是存储于可修改的全局数据区,其值依然可以改变。
观察下面代码,体会const的作用:
#include const int g_cc = 5; //全局变量存储于只读存储区 int main() { const int cc = 1; //在栈上分配空间 printf("%d\n", cc); //cc = 2; int *p = (int *)&cc; *p=3; printf("%d\n", cc); printf("g_cc = %d\n", g_cc); //g_cc = 6; //error p = (int *)&g_cc; *p=7; //在gcc中报段错误 (在bcc中不报错) printf("g_cc = %d\n", g_cc); return 0; }
在不同的编译器中,对于全局的const变量,编译效果不同。
在现代的编译器中,对于const修饰的全局变量, 会将其编译进只读存储区,一旦出现对只读存储区的修改,就会直接报错。(早期的支持标准c的编译器支持对const修饰的全局变量通过指针进行修改)
但标准c语言只是将其定义为只读,不涉及存储区。
const修饰的static将会在只读存储区中存储。
#include const int g_array[5] = {0}; void modify(int* p, int v) //不能使用void* p,是左值 { *p = v; } int main() { int const i = 0; const static int j = 1; int const arry[5] = {0}; modify((int*)&i, 2); //modify((int*)&j, 3); //error modify((int*)&array[0], 4); //modify((int*)&g_array[0], 5); //error printf("%d\n", i); printf("%d\n", j); printf("%d\n", array[0]); printf("%d\n", g_array[0]); return 0; }
const 修饰函数参数表示函数体内不希望改变参数的值;
const 修饰的函数返回至表示返回值不可改变,多用于返回指针的情形。
观察下面代码,体会const修饰参数和返回值:
注意:c语言中的字符串字面量存储于只读存储区,在程序中需要使用const char*指针。
#include const char* f(const int i) { i = 5; //error test.c:5: error: assignment of read-only location ‘i’ return "will willing"; //字面量 } int main() { const char* p = f(0); //注意此处对 p 的声明为const char* printf("%s\n", p); p[5] = '_'; //error test.c:16: error: assignment of read-only location ‘*(p + 5u)’ printf("%s\n", p); return 0; }
在linux下使用gcc编译代码,报错信息如代码注释所示。
现代的编译器在每次操作时,都会去优化操作,避免每次去内存中存取数据。
volatile可理解为“编译器警告指示字”,它告诉编译器必须每次去内存中取变量值。
volatile注意修饰可能被多个线程访问的变量,也可以修饰可能被未知因素更改的变量。
int obj=10; int a=0; int b=0; a = obj; sleep(100); ????????????????//编译器在编译的时候发现obj没有被当做左值使用, ????????????????????????????//因此会“聪明”的直接将obj替换成10,而把a,b都赋值为10. b = obj;
可是在实际的程序运行中,比如多线程或者出现中断,会在sleep(100)中修改obj的值,这个时候b的值就会与预期不一样。
const volatile int i=0;
上述语句中变量i具有什么样的特性?
存储在内存中(不让编译器优化);不能做左值。
编译器如何改变这个变量?
通过指针。
小结:
const使得变量具有只读属性,不能定义真正意义上的常量。(enum可以)
const将具有全局生命期的变量存储在只读存储区。
volatile强制编译器减少优化(多用于嵌入式和多线程),必须每次都从内存中取值。
上一篇: C语言基础学习之结构体与指针实例
下一篇: C语言基础学习之指针,数组和内存杂讲