【C++深度解析】2、C/C++ 中的 const

1 C 语言中的 const

  • const 修饰的变量是只读的,本质还是变量
  • const 修饰的局部变量在栈上分配空间
  • const 修饰的全局变量在只读存储区分配空间(修改将导致程序崩溃)
  • const 只在编译器有用,在运行期无用

const 不能定义真正意义上的常量,只是告诉编译器该变量不能出现在赋值符号的左边。C 语言中真正的常量只有 enum(枚举)

编程实验:

// 2-1.c
#include<stdio.h>
int main()
{
   const int c = 0;
   int* p = (int*)&c;
   *p = 5;
   printf("c = %d\n", c);
   return 0;
}

程序中定义了局部const 变量,存储在栈上,我们可以获取栈的地址来修改栈中的数据,C 语言中的 const 变量只是告诉编译器该变量不能出现在赋值符号的左边。

编译运行:

$ gcc 2-1.c -o 2-1
$ ./2-1
c = 5

可以看到,const 变量值依然可以改变。

2 C++中的 const

C++ 在 C 的基础上进行了优化

  • 当碰见 const 声明时在符号表中放入常量,编译过程中使用常量直接以符号表中的值替换
  • 编译过程中若发现下述情况则给对应的常量分配存储空间
    • 对 const 常量使用了 extern,需要在其他文件中使用
    • 对 const 常量使用了 & 操作符,要取地址

!!!注意:C++ 编译器虽然可能为 const 常量分配空间,但不会使用其存储空间中的值

如图所示,C++ 中用 const 定义常量时,放入符号表,使用时直接用符号表中的值替换
在这里插入图片描述
重新看一下 3-1.c 的代码

// 2-1.c
#include<stdio.h>
int main()
{
    const int c = 0;
    int* p = (int*)&c;
    *p = 5;
    printf("c = %d\n", c);
    printf("*p = %d\n", *p);
    return 0;
}

我们用 g++ 编译器编译

$ g++ 2-1.c -o 2-1
$ ./2-1
c = 0
*p = 5

程序中使用了 &c,所以为 const 类型的变量 c 分配了空间,但是打印 c 变量时,使用的是符号表中的变量 c,直接用 0 替换,改变了为 c 申请的内存中的值不改变符号表中的值。那分配的内存岂不是没有用了嘛,其实这么做是为了兼容 C 语言的特性。

2.1 C++ 中的 const 与宏

C++中的 const 常量类似于宏定义,都是替换,但又不相同

  • const 常量由编译器处理,编译器对 const 常量进行类型检查作用域检查
  • 宏定义由预处理期 处理,单纯的文本替换

编程实验:

// 2-2.c
#include<stdio.h>
void f()
{
    #define a 3
    const int b = 4;
}
void g()
{
    printf("a = %d\n", a);
    // printf("b = %d\n", b);
}
int main()
{
    const int A = 1;
    const int B = 2;
    int array[A + B] = {0};
    int i = 0;
    for (int i = 0; i < (A + B); i++)
    {
        printf("array[%d] = %d\n", i, array[i]);
    }
    f();
    g();
    return 0;
}
  • 宏定义在预处理期替换,没有作用域检查,所以第 5 行定义的宏可以在第 10 行打印,const 常量由类型检查和作用域检查,所以第 11 行打印会出错
  • 第 17 行,C 语言中 const 局部变量存储在栈上,不是真正的常量,只有在运行期才知道数组大小,编译器无法确定数组大小,所以会报错,C++ 中可以直接用符号表中的数值进行替换,可以确定数组大小,不会报错。

先用 gcc 编译器编译,第 17 行数组没法初始化

$ gcc 2-2.c -o 2-2
2-2.c: In function ‘main’:
2-2.c:17:5: error: variable-sized object may not be initialized
     int array[A + B] = {0};
     ^~~
2-2.c:17:25: warning: excess elements in array initializer
     int array[A + B] = {0};
                         ^
2-2.c:17:25: note: (near initialization for ‘array’)

再用 g++ 编译器编译:

$ g++ 2-2.c -o 2-2
$ ./2-2
array[0] = 0
array[1] = 0
array[2] = 0
a = 3

直接用符号表中的数组替代 const 常量,可以在编译器确定数组大小

3 小结

1、C 中的 const 是只读变量,C++ 中的 const 才是真正意义上的常量
2、C++ 为了兼容 C 语言中的 const 特性,可能为 const 常量分配空间

发布了248 篇原创文章 · 获赞 115 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/happyjacob/article/details/104025918
今日推荐