改变常数值

时间:2016-08-23 16:13:41

标签: c++ pointers constants

不重复。请阅读完整的问题。

#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

这怎么可能?

3 个答案:

答案 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当前值的代码,而只是使用它初始化的数字 - 它比从内存加载要快得多。

这是一种非常常见的优化技术 - 当某个条件只能在程序显示未定义的行为时发生时,优化器会认为条件永远不会发生。