第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不能作为左值

 

posted @ 2019-11-13 22:46  Hengs  阅读(390)  评论(0编辑  收藏  举报