第9课 - const 和 volatile分析
第9课 - const和volatile分析
1. const只读变量
(1)const修饰的变量是只读的,本质上还是变量,并不是真正意义上的常量 ※※ const只是告诉编译器该变量不能出现在赋值符号的左边
(2)const修饰的局部变量在栈上分配空间;const修饰的全局变量在全局数据区分配空间
(3)const只在编译期间有用(检查const修饰的变量有没有出现在赋值符号左边,如果有就会编译报错),在运行期间无用
1 #include <stdio.h> 2 3 int main() 4 { 5 const int cc = 1; 6 7 int *p = (int*)&cc; 8 9 // cc = 10; // compile error: assignment of read-only variable ‘cc’ 10 11 printf("cc = %d\n", cc); // cc = 1 12 13 *p = 10; 14 15 printf("cc = %d\n", cc); // cc = 10 16 17 return 0; 18 }
2. const全局变量的分歧
(1)在标准C语言编译器中,const修饰的全局变量仍然存储于全局数据区,并没有改变存储方式,通过指针可以隐式的修改全局变量的值。
(2)在现代C语言编译器中,将const 修饰的全局变量分配在只读存储区,改变了存储方式,通过指针隐式修改会导致程序段错误。
1 #include <stdio.h> 2 3 const int g_ci = 100; 4 5 int main() 6 { 7 int *p = (int *)&g_ci; 8 9 // g_ci = 10; // compile error: assignment of read-only variable ‘g_ci’ 10 11 printf("g_ci = %d\n", g_ci); 12 13 *p = 10; // 通过指针隐式修改 14 15 printf("g_ci = %d\n", g_ci); 16 17 return 0; 18 }
使用gcc编译执行(现代C编译器) ==> 段错误
使用bcc32编译执行(标准C编译器) ==> 修改成功
3. const的本质
(1)C 语言中的const 使得变量具有只读属性
(2)现代C编译器中的const将具有全局生命周期的变量(全局变量 + static修饰的局部变量)存储于只读存储区
【static修饰局部变量】
1 #include <stdio.h> 2 3 int main() 4 { 5 const static int si = 100; // const修饰static修饰的局部变量 6 7 int *p = (int *)&si; 8 9 *p = 1; // 使用gcc、VS2010编译执行会产生段错误 10 // 使用bcc32编译执行,可以修改si的值为1 11 12 printf("si = %d\n", si); 13 14 return 0; 15 }
【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; // const放在int前后都可以 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,j存储在只读存储区 18 modify((int*)&array[0], 3); // ok 19 modify((int*)&g_array[0], 4); // error,g_array[5]数组存储在只读存储区 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 }
4. const修饰函数参数和返回值
(1)const 修饰函数参数表示在函数体内不希望改变参数的值
(2)const 修饰函数返回值表示返回值不可改变,多用于返回指针的情形
TIP:C 语言的字符串字面量存储于只读存储区中,在程序中需要使用 const char* 指针
【const修饰函数参数与返回值】
1 #include <stdio.h> 2 3 const char* f(const int i) 4 { 5 // i = 5; // error, i不能作为左值 6 7 return "swj striving! 2019-12-23 22:23:57"; 8 } 9 10 int main() 11 { 12 char* pc = f(0); // 编译会报warning,函数f的返回值为const char* 13 14 printf("%s\n", pc); 15 16 pc[1] = '_'; // error,试图修改只读存储区中的字符串 17 18 printf("%s\n", pc); 19 20 return 0; 21 }
5. 深藏不露的volatile
(1)volatile 可理解为 "编译器警告指示字"
(2)volatile 告诉编译器必须每次去内存中取变量值
(3)volatile 主要修饰可能被多个线程访问的变量
(4)volatile 也可以修饰可能被未知因数更改的变量
6. 有趣的问题
const volatile int i = 0;
ⅰ:变量 i 具有什么样的特性? i为int型变量,每次都必须到内存取值,且i是只读变量
ⅱ:编译器如何处理这个变量? i不能作为左值