2011-08-26 131 views
4

我有点糊涂了以下情况隐藏存储在哪里?

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 

在这里我可以看到,这两个“& C”和“P”中具有相同的地址记忆。

那么'p'能够存储与'c'不同的值的隐藏机制是什么,而两者在内存中共享相同的地址空间?

回答

5
const char c = 'C'; 
char * p = const_cast<char *>(&c); 

*p = 'K'; 

这是未定义的行为。如果对象最初是const,则无法写入,即使在const_cast之后。当你处于未定义行为的领域时,对代码做什么以及如何做某些事情没有多大帮助。

11

没有“隐藏存储”。这些行

const char c = 'C'; 
char * p = const_cast<char *>(&c); // NO! 

严重违反const-correctness。您正在创建一个非const指针,该指针最初为const不要那样做。虽然演员本身没有问题,但如果您尝试解除引用p,它会调用未定义的行为,意思是任何事情都可能发生,包括您刚刚描述的行为。

这就是说,发生了什么事是编译器是folding the constantc,以便第一个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,为您所看到的行为。

+0

@R。 Martinho Fernandes:谢谢你的提醒。我已经更清楚地知道UB究竟发生了什么。 :-) –

+0

+1用于指出在编译时将常量变量替换为字面值。 –

+0

谢谢你清除我的疑惑 –

1

其他人已经解释说这是未定义的行为。可能在幕后发生的事情是,编译器发现c是常量,因此允许将其值缓存在寄存器中。当您稍后读取c的值以将其打印出来时,编译器不会从内存中读取它(它是const,因此它不能更改,对吗?),而只是使用缓存值。

1

未定义的行为。允许编译器优化(例如保存在寄存器中)它知道是不可变的事情。

标记char volatile会使编译器以预期的方式响应更多的机会。请记住,它仍然是未定义的行为仍然