C++进化后的const关键字实验剖析(const在C和C++中的对比)

关键字const经常在面试和源码中出现的关键字,我们在平时的编程中经常使用,所以专门剖析一下在C语言和C++中他们的区别和联系。


目录

1、复习巩固一下const在C中的知识点

2、实验对比分析

3、C++  中的const


1、复习巩固一下const在C中的知识点

     1)、本质:Const 修饰的只读变量,本质是变量,会分配空间,不是真正意义上的常量,不能够作为左值使用。不算常量,和常量有区别;

     2)、Const只在编译期有效,在运行期无用;

     3)、Const修饰的变量不是真正的常量,告诉编译器该变量不能出现在赋值符号的左边。到了运行的时候就管不住了。

const修饰的目标对象在何处分配空间注意事项
①、局部变量栈上 

②、全局生命周期的变量

(包括全局变量和static局部变量)

只读存储区

修改const只读变量将导致程序奔溃标准C语言编译器(bcc)不会将const修饰的全局变量存储于只读存储区,而是存储于可修改的全局数据区,其值依然可以改变。

③、函数返回值或者函数参数 

1、修饰函数参数表示在函数体内不希望改变参数的值;

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

注:c语言中的字符串字面量存储于只读存储区中,在程序中需要使用const char* 指针。

拓展:C语言中如何定义真正意义上的常量?(重要

答:其一通过枚举enum;其二通过宏定义。

2、实验对比分析

  1 #include <stdio.h>    // 实验一 : C 运行  Gcc编译
  2 
  3 int main()
  4 {
  5     const int a = 0 ;
  6     int* p = (int*)&a ;
  7     printf("C Language Test Begin...\n");
  8     printf( "a = %d \n" ,  a  ) ;
  9     printf("Operate...\n") ;                                                
 10     *p = 5;
 11     printf("a = %d\n", a ) ;
 12     printf("C Language Test End...\n") ;
 13     return 0 ;
 14 }   // a的值被改变,说明const修饰的局部变量a并不是真正意义上的常量,值仍然可以改变

结果:

 

1 #include <stdio.h>    // 实验二 :C++ 运行  G++编译 
  2 int main()
  3 {
  4      const int a = 0 ;
  5      int* p = (int*)&a ;
  6      printf("C++ Language Test Begin...\n");                                
  7      printf( "a = %d \n" ,  a  ) ;
  8      printf("Operate...\n") ;
  9      *p = 5;
 10      printf("a = %d\n", a ) ;
 11      printf("C++ Language Test End...\n") ;
 12      return 0 ;
 13   }  // 运行后c的值仍旧为0,也就是说第九行没有产生作用

结果:

由实验一和实验二可见,同一个程序在不同的编译器编译过后产生不同的结果。在C语言编译器和C++编译器编译过后的结果截然不同。

#include <stdio.h>  // 实验三 : C语言 增加输出*p的值

int main()
{
    const int a = 0 ; 
    int* p = (int*)&a ;
    printf("C Language Test Begin...\n");
    printf( "a = %d  , *p = %d \n" ,  a , *p ) ; 
    printf("Operate...\n") ; 
    *p = 5;
    printf( "a = %d  , *p = %d \n" ,  a , *p ) ; 
    printf("C Language Test End...\n") ;                                        
    return 0 ; 
}  // 

结果:

#include <stdio.h>    // 实验四 :C++ 运行  G++编译  增加*p变量的输出
int main()
{    
     const int a = 0 ; 
     int* p = (int*)&a ;
     printf("C++ Language Test Begin...\n");
     printf( "a = %d , *p = %d \n" ,  a  , *p ) ; 
     printf("Operate...\n") ;    
     *p = 5;
     printf( "a = %d , *p = %d \n" ,  a  , *p ) ; 
     printf("C++ Language Test End...\n") ;                                     
     return 0 ; 
  }  

结果:

由实验三和实验四可见,同一个程序在不同的编译器编译过后产生不同的结果。在C语言编译器和C++编译器编译过后的结果截然不同。a变量的值虽然不同,但取*p变量的值确是相同的。

分析:const这个关键字从C语言到C++语言的进化过程当中得到了很大的改变,得到了质的变化。接下来我们进行详细的讲解。

3、C++  中的const

        C++编译器在编译的过程中当碰到const修饰的标识符时,就会把这个标识符放到符号表(编译器内部的数据结构)中,之后继续向下编译;如果在后面发现有用到这个标识符时,就从符号表中将值取出来就行替换。(C++天生的使命就是兼容c语言,所以在c++中可能会给const修饰的标识符分配空间如果会分配空间,但不会使用这个空间中的值,使用的是符号表里面的那个值,分配空间只是为了兼容c语言。1、const修饰的标识符为全局,并且在其他文件中使用它,也就是说用extern修饰一个全局的常量时,就会分配存储空间 ; 2、使用了&取地址符对const常量取地址时)的。为什么不使用这个空间?==>为了兼容C语言,之前在C语言编译器编译的程序在C++编译器编译也要通过。

拓展:符号表是编译器在编译的过程中产生的一张表,这张表是编译器内部的数据结构。(也就是编译器在编译的过程中会产生各种各样的数据结构,其中一张就算符号表)。

C++中const变量的演绎过程:

C++中const从只读变量成为了真正的常量了

感觉上C++中的const常量类似于宏定义

本质是不同的:因为const常量是被编译器处理的,编译器就会对const进行类型的检查和作用域的检查

宏定义是被预处理器处理(文本替换)的宏替换之后得到是就是一个字面量,没有类型,也没有作用域,编译器根本就没有宏的定义,不知道它的存在

分析:以下程序有什么问题吗?

  #include <stdio.h>    // 实验五    C运行   gcc编译                                                                                                                         
  void f()
  {
      #define a 3
✹     const int b = 4;  // 作用域在f()内部有效,在f()之外的地方是看不到b的
  }
  void g()
  {
      printf("a = %d\n", a);
      //printf("b = %d\n", b);
  }
  int main()
  {
      printf(" C Languege Test  --------") ;
      const int A = 1;
      const int B = 2;
      int array[A + B] = {0}; 
      // const 修饰是只读变量,数组的大小到运行的时候才知道,数组大小我根本就不知道,让我怎么编译下去
      int i = 0;  
      for(i=0; i<(A + B); i++)
      {   
          printf("array[%d] = %d\n", i, array[i]);
      }     
      f();
      g();
      
      return 0;
  }

运行结果:

编译出错,提示数组没有初始化,数组大小到运行的时候才知道,编译器就不乐意了

  #include <stdio.h>  // 实验六   C++运行  g++ 编译
  void f() 
  {
      #define a 3
✹     const int b = 4;  // 作用域在f()内部有效,在f()之外的地方是看不到b的
  }
  void g() 
  {
      printf("a = %d\n", a); 
      // 宏被预处理器处理,直接进行文本替换编译器看到代码为printf("a = %d\n", 3);
      //printf("b = %d\n", b);  // error
  }
  int main()
  {
      printf("C++ Language Test ------\n") ;                                                                                                          
      const int A = 1;
      const int B = 2;
      int array[A + B] = {0}; //
      int i = 0;
      
      for(i=0; i<(A + B); i++)
      {   
          printf("array[%d] = %d\n", i, array[i]);
      }   
      f();
      g();
      return 0;
  }

运行结果:

编译通过,这时候的数组的大小是由两个真正意义上的常量运算而成的;编译器编译到定义数组大小的地方就从符号表中取值去了,A为1,B为2;数组大小为3了。从这里看出,C++中const定义的是真正意义上的常量了。

C原因还只不过是只读变量。

这个其实就是const从C语言到C++语言得到本质上的变化

在我的另一篇博文中有特别详细的介绍C++中const的实质,请点击 -> 深入浅出的剖析C++中引用的本质


如有错误,请屏幕前的你给予指正,谢谢!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值