使用指针更改常量对象的值

Changing value of constant object with pointer

本文关键字:对象 常量 指针      更新时间:2023-10-16

有这样的代码:

#include <iostream>
int main(){
  const int a = 2;
  int* ptr = (int*)&a;
  *ptr = 3;
  std::cout << &a << " " << ptr << " " << a << " " << *ptr << std::endl;
  return 0;
}

结果:

0xbf88d51c 0xbf88d51c 2 3

为什么这两个值不同?这里发生了什么?

int* ptr = (int*)&a;

这是危险的(尽管这本身不会调用UB(。但是,

*ptr = 3;

这会调用未定义行为(UB(,因为您正试图修改ptr指向的const对象。UB意味着任何事情都可能发生。请注意,a实际上是一个常量对象。

§7.1.5.1/4(C++03(说,

除了任何声明为可变的类成员(7.1.1(都可以修改外,在const对象的生存期(3.8(内任何修改const对象都会导致未定义的行为

 [Example:
 [...]
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq);    // cast required
*iq = 4;                            // undefined: modifies a const object

不要这样做。这是未定义的行为。

如果你对编译器撒谎,它会得到它的报复(c(

我有一个尚未测试的假设:

编译器为(0xbf88d51c(留出一个地址,并用2填充。int*ptr被设置为该地址,*ptr=3将3放在该地址。所以*ptr现在指向一个3。但是当它遇到值a时,编译器会硬编码"2",就像你说的是#define a 2一样。

一种验证方法是提取生成的程序集代码。

顺便说一句,我知道这是未定义的行为,但那又怎样?OP询问为什么会发生这种情况。

这是因为编译器用... " " << 2 << " " ...替换了... " " << a << " " ...

这样做是为了避免从内存中读取a的值,因为它已经是已知的、常量并且可以直接添加到汇编指令中。