我对以下情况感到困惑
const char c = 'C';
char * p = const_cast<char *>(&c);
*p = 'K';
cout << " c = " << c << endl;
cout << " *p = " << *p << endl;
printf("c's address : %u\n", &c);
printf("P is pointing to : %u\n", p);
执行时输出如下
c = C
*p = K
c's address : 3221180271
P is pointing to : 3221180271
在这里我可以观察到'&amp; c'和'p'在内存中具有相同的地址。
那么'p'能够存储与'c'不同的值的隐藏机制是什么,而两者在内存中共享相同的地址空间?
答案 0 :(得分:11)
没有“隐藏存储”。这些行
const char c = 'C';
char * p = const_cast<char *>(&c); // NO!
严重违反const
-correctness。您正在创建一个非const
指针,指向最初为const
的内容。 不要那样做。虽然演员本身很好,但是如果你试图取消引用p
它会调用未定义的行为,这意味着任何东西都可以发生,包括你刚刚描述的行为。
话虽如此,正在发生的事情是编译器是folding the constant c
,因此第一个cout
语句打印出C
。因此,编译器可能将cout
语句转换为:
cout << " c = " << 'C' << endl; // Note literal 'C' instead of variable c
cout << " *p = " << *p << endl;
因此,当第二个cout
语句通过解除引用c
来反映p
的新值时,第一个cout
语句不会受到影响。
第一个cout
没有受到影响,因为编译器认为c
的值永远不会改变(毕竟它是const
)。有了这个假设,编译器就用常量值替换了变量访问。
当你这样做时,你违反了编译器的假设:
*p = 'K'; // NO!
由于p
指向常量c
,您刚刚将其更改为K
,为您提供了所见的行为。
答案 1 :(得分:5)
const char c = 'C';
char * p = const_cast<char *>(&c);
*p = 'K';
这是未定义的行为。如果对象最初为const
,则即使在const_cast
之后也无法写入该对象。当您处于未定义行为的范围时,对于代码执行什么以及如何执行操作没有多大帮助。
答案 2 :(得分:1)
其他人已经解释说这是未定义的行为。幕后可能发生的是编译器发现c
是const,因此允许将其值缓存在寄存器中。当您稍后读取c
的值以将其打印出来时,编译器不会打扰从内存中取出它(它是const
,所以它不能更改,对吧?),但只是使用而是缓存的值。
答案 3 :(得分:1)
未定义的行为。允许编译器优化(例如保留在寄存器中)它知道不可变的事物。
标记char volatile
可能会使编译器以预期的方式响应更多。请记住,它仍然是未定义的行为