2011-08-26 110 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會使編譯器以預期的方式響應更多的機會。請記住,它仍然是未定義的行爲仍然