前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言中的const竟是个 "冒牌货"

C语言中的const竟是个 "冒牌货"

作者头像
混说Linux
发布2022-07-14 19:40:05
3860
发布2022-07-14 19:40:05
举报
文章被收录于专栏:混说Linux混说Linux

const是限定一个变量不允许改变(只读),使用const在一定程度上可以提高程序的安全性和可靠性。

代码语言:javascript
复制
// 我们先来看看const的基础知识
void main()
{
    const int a;
    int const b;         // 和前面一个意思一样,代表常整型数
    const int *c;
    int const *d;        // 和前面一个意思一样,表示所指向的内存数据不能被修改,但是本身可以修改
    int * const e;       // 指针变量不能指向其他的地址,但是它所指向内存数据可以被修改
    const int * const f; // 指针变量不能指向其他的地址,它所指向内存数据也不可以被修改
}

我们来做一个关于const的实验:

代码语言:javascript
复制
void main()
{
    const int a = 10;
    a = 11;
}
// 编译报错:error: assignment of read-only variable ‘a’

从上面代码看来const好像确实是限定一个变量不允许改变(只读),定义的变量 a 貌似变成了一个常量一样,那我们接下来继续:

代码语言:javascript
复制
void main()
{
    // 貌似定义的 a 是一个常量
    const int a = 10;
    // a = 11;
    int *p = (int *)&a;
    *p = 11;   // 通过指针间接赋值试试看
    printf("a = %d \n", a);   
}
// 编译成功   打印结果 a = 11 

我们发现貌似定义的 a是一个常量,但是通过指针却可以间接的修改 a 的值,const不是限定变量不允许修改吗?怎么被改了?这样看来C语言中const好像确实是一个“冒牌货”。

那么同样的代码,我们看看在C++中的表现:

代码语言:javascript
复制
void main()
{
  // 貌似定义的 a 是一个常量
  const int a = 10;
  // a = 11;
  int *p = (int *)&a;
  *p = 11;   // 间接赋值
  printf("a = %d \n", a);   
 
  system("pause");
}
// 打印结果 a = 10  (结果不应该是 a = 11  ?????????)
// 大家可以尝试 C 和 C++ 都进行编译对比一下。

为什么 c 和 c++ 编译的结果大相径庭?好好想想,如果是你用 c++写了一个这样的程序是用在银行后台算账的,那就麻烦大了,竟然存在这样的bug?银行每天流水那么多,账要是错了,想想都害怕吧。

其实在 c++语言里面const修饰的才算是一个真正的常量,在 c 语言中 const 可以说是个“冒牌货”。为什么会这样?其实是 c++ 编译器对 const 进行了加强,当 c++ 编译器遇到常量声明时,不会像 c 语言一样给这样const对象单独分配内存,c 语言一般是放在只读数据区,而 c ++ 编译器是把const对象放在一个符号表里面(我个人觉得放在符号表里面的其中一个原因可能是想减少一些存储操作次数),至于符号表是属于内存布局(文章:你该知道你写的程序的内存布局)中的哪一块,我也不知道,写 c++ 编译器的人才知道。

在 c++ 中使用 const 对象(比如打印这个对象)的时候,就会从符号表里面把对象的值拿出来使用,比如printf("a = %d \n", a); ,这时候就是把 a 的值10拿出来使用,但是当你对 a 取地址(&a)的时候,c++ 编译器会为这个a单独分配一个内存空间,如果定义一个指针指向这个内存空间(int *p = (int *)&a;),那么这个指针指向的是这个新分配的一个内存空间,然后通过这个指针间接修改这个值(*p = 11;),这时候修改的其实新分配的这个空间的值,不管你间接修改的这个值是11、20、30还是100,都和符号表原本的 a 的值没有任何关系,所以使用 a 的时候打印出来的结果是 a = 10,这就是符号表,是 c++ 对 c 的一些扩展,这样就会发现 c++ 编译器把 const 变成符号表这个手段确确实实把 const 修饰的变量变成了一个常量,结论就是在 c 语言里面 const 确实是一个“冒牌货”。

这时候可能还有一个疑问,这个新分配的内存到底存不存在?这个简单,我们加一句打印就行:

代码语言:javascript
复制
void main()
{
  // 貌似定义的 a 是一个常量
  const int a = 10;
  // a = 11;
  int *p = (int *)&a;
  *p = 11;   // 间接赋值
 
  printf("*p = %d \n", *p);   // 加上这句打印
  printf(" a = %d \n", a);   
 
  system("pause");
}
// 打印结果:*p = 11     a = 10

从打印可以看出单独分配的这个内存空间值是11,和原来的 a 是不同的两个概念,这就是在 C++ 中 const 的符号表的实现机制。分享是一种积极的生活态度

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 混说Linux 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档