不重复。请阅读完整的问题。
#include<iostream>
using namespace std;
int main()
{
const int a = 5;
const int *ptr1 = &a;
int *ptr = (int *)ptr1;
*ptr = 10;
cout<<ptr<<" = "<<*ptr<<endl;
cout<<ptr1<<" = "<<*ptr1<<endl;
cout<<&a<<" = "<<a;
return 0;
}
输出:
0x7ffe13455fb4 = 10
0x7ffe13455fb4 = 10
0x7ffe13455fb4 = 5
这怎么可能?
答案 0 :(得分:2)
您不应该依赖未定义的行为。看看编译器对你的代码做了什么,特别是最后一部分:
cout<<&a<<" = "<<a;
b6: 48 8d 45 ac lea -0x54(%rbp),%rax
ba: 48 89 c2 mov %rax,%rdx
bd: 48 8b 0d 00 00 00 00 mov 0x0(%rip),%rcx # c4 <main+0xc4>
c4: e8 00 00 00 00 callq c9 <main+0xc9>
c9: 48 8d 15 00 00 00 00 lea 0x0(%rip),%rdx # d0 <main+0xd0>
d0: 48 89 c1 mov %rax,%rcx
d3: e8 00 00 00 00 callq d8 <main+0xd8>
d8: ba 05 00 00 00 mov $0x5,%edx <=== direct insert of 5 in the register to display 5
dd: 48 89 c1 mov %rax,%rcx
e0: e8 00 00 00 00 callq e5 <main+0xe5>
return 0;
e5: b8 00 00 00 00 mov $0x0,%eax
ea: 90 nop
eb: 48 83 c4 48 add $0x48,%rsp
ef: 5b pop %rbx
f0: 5d pop %rbp
f1: c3 retq
当编译器看到一个常量表达式时,它可以决定(依赖于实现)将其替换为实际值。
在这种特殊情况下,g ++甚至没有-O1
选项就做到了!
答案 1 :(得分:1)
当您调用未定义的行为时,一切皆有可能。
在这种情况下,您将使用此行强制转换constness:
int *ptr = (int *)ptr1;
你很幸运,堆栈上有一个地址需要更改,这就解释了为什么前两个打印输出10
。
第三个打印输出5
,因为编译器通过对5
进行硬编码来优化它,从而假设a
不会被更改。
答案 2 :(得分:0)
这当然是未定义的行为,但我强烈支持理解未定义行为的症状,以便发现一个。观察到的结果可以用以下方式解释:
const int a = 5
定义的整数常量。编译器现在假定在整个函数的持续时间内永远不会修改值,所以当它看到
时cout<<&a<<" = "<<a;
它不会生成重新加载a
当前值的代码,而只是使用它初始化的数字 - 它比从内存加载要快得多。
这是一种非常常见的优化技术 - 当某个条件只能在程序显示未定义的行为时发生时,优化器会认为条件永远不会发生。