6 const 和 volatile

1 const 定义一个只读变量,而不是常量

  • const 修饰的变量是只读的,其本质还是变量

    const 修饰的变量不是真正的常量,它只是告诉编译器该变量不能出现在赋值符号的左边

  • const 修饰的局部变量上分配空间;const 修饰的全局变量全局数据区分配空间,所以 const 修饰的变量在内存中是分配了空间的,那么就可以修改这个空间里的值

  • const 只在编译期对编译器有用,在运行期无用,即可以修改所修饰的变量的值

2 const 全局变量的分歧

  • 现代C语言编译器中,const 全局变量存储于只读存储区,修改 const 全局变量将导致程序崩溃

  • 标准C语言编译器中不会将 const 修饰的全局变量存储于只读存储区,而是存储于可修改的全局数据区,所以其值可以改变

  • 示例1:const 修饰局部变量 => read-only variable,不可直接修改

    • Demo

      #include <stdio.h>
      
      int main()
      {
          //const修饰的局部变量,即所谓的“常量”
          const int cc = 1;
          printf("cc = %d\n",cc);
          
          cc = 3;
          printf("cc = %d\n",cc);
          
          return 0;
      }
      
    • GCC 编译

      test1.c: In function 'main':
      test1.c:9: error: assignment of read-only variable 'cc'
      
  • 示例2:const 修饰局部变量,可利用指针修改

    • Demo

      #include <stdio.h>
      
      int main()
      {
          //const修饰的局部变量,即所谓的“常量”
          const int cc = 1;
          int* p = (int*)&cc;
          printf("cc = %d\n",cc);
          
          *p = 3;
          printf("cc = %d\n",cc);
          
          return 0;
      }
      
    • GCC 编译

      cc = 1
      cc = 3
      
  • 示例3:const 修饰全局变量,read-only variable

    • Demo

      #include <stdio.h>
      
      //const 修饰全局变量
      const int g_cc = 2;
      
      int main()
      {
          printf("g_cc = %d\n",g_cc);
          
          g_cc = 4;
          printf("g_cc = %d\n",g_cc);
          
          return 0;
      }
      
    • GCC 编译

      test3.c: In function 'main':
      test3.c:10: error: assignment of read-only variable 'g_cc'
      
  • 示例4:利用指针修改 const 修饰的全局变量

    • Demo

      #include <stdio.h>
      
      //const 修饰全局变量
      const int g_cc = 2;
      
      int main()
      {
          printf("g_cc = %d\n",g_cc);
          
          int* p = (int*)&g_cc;
          
          *p = 4;
          printf("g_cc = %d\n",g_cc);
          
          return 0;
      }
      
    • GCC 编译通过,运行出错!

      g_cc = 2
      段错误
      
    • BCC 运行

      g_cc = 2
      g_cc = 4
      

3 const 的本质

  • C语言中的 const 使得变量具有只读属性

  • 现代C编译器中 const具有全局生命周期的变量(全局生命周期的变量有:全局变量,static 修饰的局部变量)存储于只读存储区,其值不可改变

  • const 不能定义真正意义上的常量,只是一个只读变量

  • 示例5:修改被 const 修饰的具有全局生命周期的变量

    • Demo

      #include <stdio.h>
      
      //const 修饰的普通全局数组,其中每个元素都为只读变量
      const int g_array[5] = {0};
      
      void modify(int* p,int v)
      {
          *p = v;
      }
      
      int main()
      {
          const int i = 0;  // const 修饰的普通局部变量
          const static int j = 0;  // const 修饰的 static 局部变量
          const int array[5] = {0};  // const修饰的普通局部数组
          
          modify((int*)&i,1);  // ok
          modify((int*)&j,2);  // error
          modify((int*)&array[0],3);  // ok
          modify((int*)&g_array[0],4);  // error
          
          printf("i = %d\n",i);
          printf("j = %d\n",j);
          printf("array[0] = %d\n",array[0]);
          printf("g_array[0] = %d\n",g_array[0]);
          
          return 0;
      }
      
    • 编译运行

      段错误
      
    • 注释18,20行

      #include <stdio.h>
      
      //const 修饰的普通全局数组,其中每个元素都为只读变量
      const int g_array[5] = {0};
      
      void modify(int* p,int v)
      {
          *p = v;
      }
      
      int main()
      {
          const int i = 0;  // const 修饰的普通局部变量
          const static int j = 0;  // const 修饰的 static 局部变量
          const int array[5] = {0};  // const修饰的普通局部数组
          
          modify((int*)&i,1);  // ok
          //modify((int*)&j,2);  // error
          modify((int*)&array[0],3);  // ok
          //modify((int*)&g_array[0],4);  // error
          
          printf("i = %d\n",i);
          printf("j = %d\n",j);
          printf("array[0] = %d\n",array[0]);
          printf("g_array[0] = %d\n",g_array[0]);
          
          return 0;
      }
      
    • 编译运行

      i = 1
      j = 0
      array[0] = 3
      g_array[0] = 0
      

4 const 修饰函数参数和返回值

  • const 修饰函数参数表示在函数体内不希望改变参数的值

  • const 修饰函数返回值表示返回值不可改变,多用于返回指针的情形

  • C 语言中的字符串字面量存储于只读存储区中,在程序中需要使用 const char* 指针来指向

  • 示例:字符串字面量

    • Demo1:利用 char* 指向一个字符串字面量,错误行为!

      #include <stdio.h>
      
      const char* f(const int i)
      {
          i = 5;  //error
          return "ABCD EFG";
      }
      
      int main()
      {
          char* pc = f(0);
          
          printf("%s\n",pc);
          
          pc[4] = '_';
          
          printf("%s\n",pc);
          
          return 0;
      }
      
    • 编译

      test.c: In function 'f':
      test.c:5: error: assifnment of read-only location 'i'
      test.c: In fuction 'main':
      test.c:11: warning: initialization discards qualifiers from pointer target type
      
    • Demo2

      #include <stdio.h>
      
      const char* f(const int i)
      {
          return "ABCD EFG";
      }
      
      int main()
      {
          char* pc = f(0);
          
          printf("%s\n",pc);
          
          pc[4] = '_';
          
          printf("%s\n",pc);
          
          return 0;
      }
      
    • 编译

      test.c: In fuction 'main':
      test.c:11: warning: initialization discards qualifiers from pointer target type
      
    • 运行

      ABCD EFG
      段错误
      
    • Demo3:利用 const char* 接收函数的返回值,不可修改

      #include <stdio.h>
      
      const char* f(const int i)
      {
          return "ABCD EFG";
      }
      
      int main()
      {
          const char* pc = f(0);
          
          printf("%s\n",pc);
          
          pc[4] = '_';
          
          printf("%s\n",pc);
          
          return 0;
      }
      
    • 编译

      test.c: In fuction 'main':
      test.c:14: error: assignment of read-only location '*(pc+4u)'
      

5 volatile 关键字

  • volatile 可理解为“编译器警告指示字”

  • volatile 告诉编译器必须每次去内存中取变量值

  • volatile 主要修饰可能被多个线程访问的变量

  • volatile 也可以修饰可能被未知因数更改的变量

  • 示例

    • 编译器在编译的时候发现 obj 没有被当作左值使用,因此会直接将 obj 替换成 10,而把 a 和 b 都赋值为 10
    • 如果暂停 100ms,在这段时间内很可能 obj 变量这段内存空间很可能被线程所改变,那么 b 所得到的值就不应该是 10 了
    • 这种情况下,应该用 volatile 修饰 obj 变量
    int obj = 10;
    
    int a = 0;
    int b = 0;
    
    a = obj;
    
    sleep(100);
    
    b = obj;
    
posted @ 2020-09-01 21:02  nxgy  阅读(141)  评论(0)    收藏  举报