鱼C论坛

 找回密码
 立即注册
查看: 3633|回复: 18

诡异的const 你真的懂吗???

[复制链接]
发表于 2012-9-14 18:24:59 | 显示全部楼层 |阅读模式
1鱼币
A、在C++编译器中:
  const int a=10;
  int *b=(int*)&a;
  std::cout<<a<<std::endl;//输出10
  (*b)=1;
  std::cout<<a<<std::endl;//输出10
B、在C编译器中:
  const int a=10;
  int *b=(int*)&a;
  printf("%d\n",a);//输出10
  (*b)=1;
  printf("%d\n",a);//输出1

那位大牛能解释一下,为什么这样啊?const 修饰的变量 在C和C++里面不同。我一直认为 A根本编译不过,因为C++中的const 就是把a变成了常量,改变 是编译不过的,可是事实是通过编译了,在C里面编译通过还可以理解,因为C中const 修饰的 只能说明是只读的,是可以修改其值的,求解???在 A中为什么能编译通过,而且在C与C++中结果不同???

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-9-14 19:29:47 | 显示全部楼层
不知道对不对啊 我的理解是:
const int a=10 当操作系统执行了这条指令 就已经为变量a分配了内存空间了 也证明a有了一个地址
那就可以理解 int *b = (int *)&a;  操作系统执行这句语句是将 const int a 强制转换为指针变量了 然后把
系统分配给a的地址赋值给了 *b ,也就是说 a的值并没有发生变化 *b只是得到了 a的地址
所以后面的两句输入都应该还是 a的原来的值 10

a作为常量 值一直没有发生变化 它与b之间没有做值传递  只是做了地址之间的赋值
a还继续保留了自己原有的值和地址  , b的地址里面存放了a的地址而已
所以是应该可以通过编译的

如果说的有误  请大牛纠正 感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2012-9-14 20:02:46 | 显示全部楼层

可以编译通过,但是 在c和C++里面  结果不一样,从我反汇编的结果来看,不管在c还是c++的里面在*b赋值之后 a的存储空间的值确实是改变了,只是到输出这一步的时候,在C里面会再一次的读a所在内存的内的值,而在C++里面,则是直接把a原来的值 拿来用 没有再一次去读a所在内存内的值!!估计是编译器的在不同语言下的方式不一样吧  在C++里面 如果把const 改为volatile 就能输出和C一样的效果啦!从这更能断定是编译器在搞鬼,在C++里不告诉编译器 a是容易改变的值 他就只读一次 就认为不会变!哎 实在是难搞啊 害的我面试题都做错了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-14 20:02:50 | 显示全部楼层
  1.   const int a=10;
  2.   int *b=(int*)&a;
  3.   std::cout<<a<<std::endl;//输出10
  4.   (*b)=1;
  5.   std::cout << a << std::endl;//输出10
  6.   std::cout << *((int *)&a) << std::endl;//输出1
复制代码
a的值确实改变了,c++里  int *b=&a;是不允许的,但是这里进行了类型转换,
骗过了编译器。当输出a的值时,编译器看到a是const类型的,就不会从它的内存
读数据压栈,而是直接把那个10压栈,可能默认const类型值不能改变。所以输出10.
当访问a内存里数据时其实已经变为1了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-14 20:36:31 | 显示全部楼层
呜呜。。没分了。。LZ都说光了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2012-9-14 21:30:12 | 显示全部楼层
无星之夜 发表于 2012-9-14 20:36
呜呜。。没分了。。LZ都说光了

那只是我的认为,希望各位仁兄各抒己见哦!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-15 03:16:20 | 显示全部楼层
据说是因为c++对指针用法的限制~~~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-15 10:23:00 | 显示全部楼层
msdn的说法:
In C++, you can use the const keyword instead of the #define preprocessor directive to define constant values.

这是不是在说:C++里的const相当于#define,所以 std::cout<<a<<std::endl;//输出10

而C里面没有这个效果。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2012-9-15 12:27:19 | 显示全部楼层
贝壳 发表于 2012-9-15 10:23
msdn的说法:
In C++, you can use the const keyword instead of the #define preprocessor directive to ...

我感觉那句话的意思 是最好用const代替宏定义  在C++里面 而不是等价的意思!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-15 13:08:00 | 显示全部楼层
是这样的:
1.在C语言里,const修饰的并不是真正的常量,仅仅是不可写的变量。举个例子,C数组的长度必须是常量表达式,你写
int v[10];正确

const int N = 10;
int v[N];就错误。

2.在C++里,const修饰的是真的常量,该常量并没有实际分配存储单元,而是在编译的时候直接将常量出现的位置替换为常量的值,这个称为“常量折叠”。所以前面的例子在C++里可以编译通过。


3.最容易令人产生疑问的地方在于:C++中,你居然可以对常量取地址(前面说到不为常量分配存储单元,如何还能取常量的地址呢?)
当C++中对常量单元取地址时,编译器就会在内存中复制一份该常量的副本,通过这个地址是无法改变常量的值的,因为该地址只是一个常量的副本。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2012-9-15 14:16:47 | 显示全部楼层
仰望天上的光 发表于 2012-9-15 13:08
是这样的:
1.在C语言里,const修饰的并不是真正的常量,仅仅是不可写的变量。举个例子,C数组的长度必须是 ...

但是从反汇编后 看的话 值确实是被改变了啊,只是  再次输出a的值的时候,编译器没有再去那个地址读数据,而是根据自己的"经验" 直接输出原来的值!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-15 17:11:25 | 显示全部楼层
拉登o睡觉 发表于 2012-9-15 14:16
但是从反汇编后 看的话 值确实是被改变了啊,只是  再次输出a的值的时候,编译器没有再去那个地址读数据, ...

我不是说了,改变的是副本的值了吗?原先的常量没有被分配空间。这个和你看到的现象是一致的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2012-9-15 19:49:31 | 显示全部楼层
仰望天上的光 发表于 2012-9-15 17:11
我不是说了,改变的是副本的值了吗?原先的常量没有被分配空间。这个和你看到的现象是一致的。

但是 从反汇编看 定义语句 确实分配了空间啊 对于本程序是存储在ebp-4的位置
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-15 20:39:14 | 显示全部楼层
分配空间是由于这个程序段const int a=10;之后含有&a这样的代码。
我前面说过,当对常量取地址的时候。编译器将会为该常量创建一个副本,这个空间是为这个副本分配的。
至于为什么此时要分配空间,我的理解是:你都已经对常量取地址了,天晓得你后面要不要读这个地址的内容;不如分配个空间作为常量的副本,这样你读该地址内容的时候就不会出问题。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-15 20:41:15 | 显示全部楼层
const int a=10;的处理你在汇编代码中是看不到的,因为在编译的时候做了“常量折叠”处理,类似于C中的宏替换,所有出现a的地方都被10替换了。所以你看到的分配空间,就是给该常量副本分配的空间,与该常量没有任何关系。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2012-9-17 22:32:53 | 显示全部楼层
学习了 仰望天上的光老师 一直是我的偶像啊  
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-6-16 10:33:40 | 显示全部楼层
过来学习一下。。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-6-16 14:51:54 | 显示全部楼层
学习了,很深奥的样子
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-21 21:42:59 | 显示全部楼层
楼上的解释的好详细啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-6-6 14:41

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表