const只读变量:
const全局变量的分歧:
测试程序与运行结果如下:
通过指针修改const全局变量的例子:
结果如下:
可见修改const的全局变量会导致程序崩溃。
原因是const全局变量被存储于只读存储区了。
上图是gcc的结果。
但是这个程序在bcc编译器下可以正常运行。
bcc是一款较早的编译器,这说明并没有编译进入只读存储区。
VC编译器也会运行崩溃,说明也是存到了只读存储区。
const的本质:
由上面的实验可知,现代编译器进行编译时,const修饰的全局变量会进入只读存储区,static变量也在全局存储区,因此const修饰的static变量也会放到只读存储区。
const的本质分析示例程序:
1 #include <stdio.h> 2 3 const int g_array[5] = {0}; 4 5 void modify(int* p, int v) 6 { 7 *p = v; 8 } 9 10 int main() 11 { 12 int const i = 0; 13 const static int j = 0; 14 int const array[5] = {0}; 15 16 modify((int*)&i, 1); // ok 17 modify((int*)&j, 2); // error 18 modify((int*)&array[0], 3); // ok 19 modify((int*)&g_array[0], 4); // error 20 21 printf("i = %d\n", i); 22 printf("j = %d\n", j); 23 printf("array[0] = %d\n", array[0]); 24 printf("g_array[0] = %d\n", g_array[0]); 25 26 return 0; 27 }
17与19行会产生运行时错误。
去掉引起崩溃的行,运行结果如下:
bcc编译器编译的可执行程序不会引起崩溃,结果如下:
const修饰函数参数和返回值:
字符串字面量存储于只读存储区。
const修饰返回值一般用于返回指针的情形。
示例程序如下:
1 #include <stdio.h> 2 3 const char* f(const int i) 4 { 5 i = 5; 6 7 return "Delphi Tang"; 8 } 9 10 int main() 11 { 12 char* pc = f(0); 13 14 printf("%s\n", pc); 15 16 pc[6] = '_'; 17 18 printf("%s\n", pc); 19 20 return 0; 21 }
第5行会编译出错,12行会报警告,因为将一个const char*赋值给char*。当我们在第16行去修改pc指向的内存,会引起崩溃。
深藏不漏的votalite:
现代编译器会做很多优化,不能保证每次读取变量的值都去内存中读,为了提高效率,CPU可能在寄存器中读取变量的值。
有趣的问题:
结果是,i是一个只读变量,不能出现在赋值符号的左边,而且编译器不会对它优化(因为有volatile)。
volatile主要用在多线程编程和嵌入式开发中。
小结: