当我使用 *(int*)&x 赋值给常量值 x 时会发生什么?

What happens when I use *(int*)&x to assign to a constant value x?

本文关键字:常量 什么 赋值 int      更新时间:2023-10-16

我尝试了以下代码:

#include <iostream>
using namespace std;
struct MyClass {
const int x;
};
int main() {
MyClass c = {3};
const int *p = &c.x;
cout << "x = " << c.x << endl;
cout << "&x = " << &c.x << endl;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "*(&x) = " << *(&c.x) << endl;
cout << endl;
*(int*)&c.x = 4;
cout << "x = " << c.x << endl;
cout << "&x = " << &c.x << endl;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "*(&x) = " << *(&c.x) << endl;
cout << (p == &c.x) << endl;
cout << (*p == *(&c.x)) << endl;
return 0;
}

然后我得到以下答案:

x = 3
&x = 0x61fe98
p = 0x61fe98
*p = 3
*(&x) = 3
x = 4
&x = 0x61fe98
p = 0x61fe98
*p = 4
*(&x) = 4
1
1

看来我已经成功更改了常量整数 x 的值。但是当我直接在main()中而不是在类中声明x时,我得到了完全不同的答案。

#include <iostream>
using namespace std;
int main() {
const int x = 3;
const int *p = &x;
cout << "x = " << x << endl;
cout << "&x = " << &x << endl;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "*(&x) = " << *(&x) << endl;
cout << endl;
*(int*)&x = 4;
cout << "x = " << x << endl;
cout << "&x = " << &x << endl;
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
cout << "*(&x) = " << *(&x) << endl;
cout << endl;
cout << (p == &x) << endl;
cout << (*p == *(&x)) << endl;
return 0;
}

结果是

x = 3
&x = 0x61fe98
p = 0x61fe98
*p = 3
*(&x) = 3
x = 3
&x = 0x61fe98
p = 0x61fe98
*p = 4
*(&x) = 3
1
0

这真的很奇怪,(p == &x)是真的,但(*p == *(&x))是假的!!我不知道第二个代码是怎么回事。

你正在做的事情是未定义的行为,所以任何事情都可能发生。C++标准说:

除了可以修改声明mutable(10.1.1) 的任何类成员之外,任何在const对象的生存期内修改其生存期 (6.8) 的尝试都会导致未定义的行为。

和:

[注意:根据对象的类型,通过指针、左值或指向数据成员的指针的写入操作,由丢弃常量限定符的const_cast产生未定义的 行为 (10.1.7.1)。— 尾注]

因此,您可以丢弃"const"来获取int*但尝试通过该指针实际修改变量是未定义的。

您可以丢弃const的原因是它实际上可能并不指向常量:

int i = 0;
const int* p = &i;
*(int*)p = 1;      // OK, because p points to a non-constant
const int j = 0;
const int* q = &j;
*(int*)q = 1;      // NOT OK, because q points to a constant

在第二个示例中,编译器在优化时做出假设,基于它知道常量值不会更改的事实,因此它不会费心测试其值。这个假设是正确的,因为正确的程序永远不会改变常量的值。您的程序不正确,但这意味着编译器不需要给出合理的结果。