返回信息流代码如图
输出结果如图
求解释。。
这是一条镜像帖。来源:北邮人论坛 / cpp / #89102同步于 2015/10/16
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
[讨论]一址两值?
Jason2031
2015/10/16镜像同步14 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
int *pi = const_cast<int*>(&a);
const_cast可以把const修饰符去掉,这个没问题。
*pi = 200;
a本身是被const修饰的,它的意思是“程序员保证不去修改a里面存的值,一旦试图修改,结果是未定义行为。”这个表达式就是有“未定义行为”,意思是“C语言的规范不规定C语言的实现(编译器、CPU、操作系统等合在一起)如何去执行这个语句”,即“什么都允许发生,从什么都不发生到机器冒烟都可以”。
第二个转换:
int &ra = const_cast<int&>(a1);
其实这里并没有转换什么,int&的意思是“int的引用”,ra将拥有和a1同样的存储空间,也就是ra就是a1的别名了。
至于为什么这次碰巧看到“一址两值”,有可能编译器因为看到了const修饰符,把所有使用a的地方都直接替换成100了,根本没有考虑“a里面的值会变”这种可能性,毕竟const的意思就是程序员向编译器保证“a不会变,如果我往a里面写,后果自负”。并不是必须有这种行为。换一个编译器、操作系统、CPU,或者调一下编译器的参数,结果就有可能变。
编译器可以换一种实现方法:把这个const int a = 100分配到只读内存区域去。这样,读的时候看到100,写的时候会segmentation fault。
其实这个问题以前讨论过,竟然还是面试题。但我记得阿里技术挺厉害的,不该出这样的题吧。 http://bbs.byr.cn/#!article/CPP/86336
感觉问题出在你的const int a1=10;这个声明?const的值不能变,编译的时候直接就将下面第一个cout中的a1给替代成10了
然后实际上桟里面0x7fff5fbff78c这个地址的值确实被你ra引用改成了200,嗯
然后我想问:定义一个常量的引用这种方式科学么。。。以上只是猜测
求助暖女神给个说法吧@nuanyangyang
学习了~那这样的话那到底哪个变量存在哪个地址啊。。
【 在 nuanyangyang 的大作中提到: 】
: 至于为什么这次碰巧看到“一址两值”,有可能编译器因为看到了const修饰符,把所有使用a的地方都直接替换成100了,根本没有考虑“a里面的值会变”这种可能性,毕竟const的意思就是程序员向编译器保证“a不会变,如果我往a里面写,后果自负”。并不是必须有这种行为。换一个编译器、操作系统、CPU,或者调一下编译器的参数,结果就有可能变。
: 编译器可以换一种实现方法:把这个const int a = 100分配到只读内存区域去。这样,读的时候看到100,写的时候会segmentation fault。
: 其实这个问题以前讨论过,竟然还是面试题。但我记得阿里技术挺厉害的,不该出这样的题吧。 http://bbs.byr.cn/#!article/CPP/86336
: ...................
我记得这个问题出现过
之所以出现原值,应该是
程序代码在预编译的时候,将代码当中的所有a 替换成了100,你说,a都是常量了这样做会肯定会节省运行时间,编译器会放弃这个改善程序运行效率的机会吗? 毕竟运行时节省了访问内存的时间啊
运行时访问的肯定是改变过后的值了,这应该是没有什么疑问的。
至于你说 这样也太毛了吧,哪有这样的,不是说不能改变的嘛 然而他就是这样的
以为的有限知识推断的答案 仅供参考
其实我也是这样想的
【 在 shan10211865 (IM_by||落雨大||水浸街||担柴上街卖) 的大作中提到: 】
: 我记得这个问题出现过
: 之所以出现原值,应该是
: 程序代码在预编译的时候,将代码当中的所有a 替换成了100,你说,a都是常量了这样做会肯定会节省运行时间,编译器会放弃这个改善程序运行效率的机会吗? 毕竟运行时节省了访问内存的时间啊
: ...................
通过『我邮2.0』发布
【 在 Jason2031 的大作中提到: 】
: 学习了~那这样的话那到底哪个变量存在哪个地址啊。。
:
C语言会给你一个印象:变量就是存储空间,里面储存一个值。C语言的“语义”确实也如此。
但实际实现中,编译器往往会更聪明:如果一个变量可以放在寄存器里,那就放在寄存器里,既然不在内存里,自然也就没有“地址”;如果用寄存器存储不好实现(比如要被别的函数改,那种情况下,用内存更容易实现),那就改用内存。所以,“哪个变量存在哪个地址里”,没有答案。C语言并不给你提供“地址”这个概念。C语言的指针是“对一个存储空间的引用”,并没有说是地址。
所以,你能依赖的只有:
1. 变量是存储空间,赋值语句可以往里面存储值,对这个变量求值的时候会读出它里面的值。(即:不要问“存储空间”是什么,知道它能读写就行了。不管编译器把它分配在寄存器里还是分配在内存里,还是直接转换成指令里的立即数了,还是因为优化把它删掉了,都必须伪装得让你相信C语言的“存储空间”语义。)
2. 用const修饰的存储空间只可以读,不可以写。一旦写了,任何事情都可能发生。
【 在 cyf333333 的大作中提到: 】
: 感觉问题出在你的const int a1=10;这个声明?const的值不能变,编译的时候直接就将下面第一个cout中的a1给替代成10了
: 然后实际上桟里面0x7fff5fbff78c这个地址的值确实被你ra引用改成了200,嗯
: 然后我想问:定义一个常量的引用这种方式科学么。。。以上只是猜测
: ...................
这样解释说得通:可以认为,这一次,编译器给a1分配了内存空间(编译器可以不这样做,可以不给a1分配内存空间),而且空间碰巧分配在了栈上(编译器可以不这样做,可以分配在堆里,可以分配在只读存储区,可以分配在静态存储区……),而且操作系统并不阻止程序对栈上的内存的修改(操作系统可以不这样,如果CPU允许非常精准的,比如精准到字的访问控制,操作系统可以阻止对这个地址的写操作),然后被修改成了200,然后下一次对这个a1求值的时候,编译器没有从那块内存空间里读a1(编译器可以不这样做,它可以让程序去读那块内存,毕竟const只是说不许修改,没说修改了会怎么样),而是直接把a1原来的值写到机器指令里,成为立即数(编译器也可以不这样做,如果a1在别的地址里还有备份(C语言没说不许这样做),可以从那里读),因此对0x7fff5fbff78c这个地址的写操作碰巧没有影响到下一次对a1的求值(我没说“对a1的求值”是“对0x7fff5fbff78c的读取”吧?)。