[英]Two different values at the same memory address
#include <iostream>
using namespace std;
int main() {
const int N = 22;
int * pN = const_cast<int*>(&N);
*pN = 33;
cout << N << '\t' << &N << endl;
cout << *pN << '\t' << pN << endl;
}
22 0x22ff74
33 0x22ff74
为什么同一个地址有两个不同的值?
为什么同一个地址有两个不同的数据?
没有。 允许编译器优化对 const 的任何提及,就好像您在其中编写了它的编译时值一样。
请注意,如果您执行诸如写入为 const 保留的内存之类的讨厌技巧,编译器还可以生成在运行时擦除硬盘的代码。
您会在*pN = 33;
行得到未定义的行为 ,因为您正在修改 const 值。 任何事情都有可能发生。 不要这样做。
不过,您的编译器很可能只是进行了优化。 在行中:
cout << N << '\t' << &N << endl;
它知道N
是一个值为 22 的常量表达式,因此只需将行更改为:
cout << 22 << '\t' << &N << endl;
在您的下一行,您获取N
的地址处的值,将其“设置”为 33。(但实际上,您所做的只是删除了有关程序状态的任何保证。)
通过声明N
是 const,您已承诺不会修改它。 然后你去修改它。 这打破了编译器所做的假设之一,因此程序的行为不正确。
这被称为“未定义的行为”——在违反语言中的假设之后,程序的行为是完全未定义的。 它不需要产生那个输出——它可以为两者产生33
或42
,或者崩溃,或者擦除你的硬盘驱动器,或者通过你的鼻道召唤恶魔。 所以,不要修改 const 值:)
int * pN = const_cast<int*>(&N);
*pN = 33;
您的代码调用未定义行为1 ,因为您正在修改const
限定变量/对象的内容。
1)未定义行为:行为,例如在使用错误程序结构或错误数据时可能出现的行为,标准对此没有任何要求。[注意:允许的未定义行为范围从完全忽略具有不可预测结果的情况到在以环境特征的文件化方式翻译或程序执行(有或没有发出诊断消息),终止翻译或执行(发出诊断消息)。
您可以将 N 声明为 volatile,以强制编译器从变量的内存位置获取当前值。
volatile const int N = 22;
const_cast 在您的代码中,只需将指针“Pn”交给“N”,通过它可以修改“N”。 “N”的地址与移交的指针“Pn”保持一致
我有同样的问题( 为什么即使使用 const_cast<int*> 我也无法修改 const int 的内容? )。 我想每个人都在这里回答得很好。 只需添加编译器的程序集输出
这是我的原始代码
const int y = 7;
int* a = new int;
a = const_cast<int*>(&y);
*a = 8;
std::cout << (int)*(&y) << std::endl;
这是汇编输出
std::cout << (int)*(&y) << std::endl;
00381CB6 push offset std::endl<char,std::char_traits<char> > (03813C5h)
**00381CBB push 7**
00381CBD mov ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (03900ACh)]
00381CC3 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (03900B8h)]
00381CC9 mov ecx,eax
00381CCB call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (03900BCh)]
所以编译器只会在编译期间用它的实际值替换 const 变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.