2013-12-22 152 views
1

我正在閱讀一本C++書籍,並且遇到了靜態轉換的問題。這裏是一個函數:C++中的類型轉換

void fun(int*pi) 
{ 
    void *pv = pi 
    int *pi2 = static_cast<int*>(pv); //explicit conversion back to int* 
    double *pd3 = static_cast<double*>(pv); //unsafe 

} 

最後一條語句:

double*pd3 = static_cast<double*>(pv); 

被認爲是不安全的。我不明白爲什麼它被認爲是不安全的。

+2

因爲你告訴編譯器有一個'pv'指向的'double'對象,而事實上並沒有。 – 2013-12-22 18:10:43

+0

因爲用於int的存儲大大小於double的存儲。你最終可能會使用錯誤的數據,或者甚至覆蓋變量來跟隨/在任何pi指向的前面。 – cup

+0

提示:'int'和'double'不是同一個東西,它們不一定佔據相同的空間。 – Shoe

回答

6

演員重新詮釋有針對性的對int位,再加上可能還有一些以下的內存位(如果有的話!),作爲double值。 (1)典型地大於int,並且(2)具有一些內部結構。點(1)意味着任何對解除引用的結果指針的使用都可能訪問超出int而無法訪問的內存。

點(2)表示的任意的位模式,可能是無效作爲double位模式,並可能導致硬件異常又名「陷阱」時,它的使用。從C++的角度來看,這是Undefined Behavior。從實際的編程角度來看,它通常是一個「崩潰」。

與此相反,訪問double的位作爲int通常在實踐安全的,即使它的正式UB,因爲(1)的int通常小於或在尺寸上等於double,和(2)一個int通常沒有任何無效位模式。但是,根據編譯器選項,編譯器可能不樂意直接執行此操作。


在上面,我忘了提對準,如洛基阿斯塔在評論中指出。這是不安全的原因(3)。舉例來說,在某些給定的實現中,可以允許int具有4的倍數的地址,而double可能需要駐留在8的倍數的地址處。然後,解除引用的指針可以訪問double在一個不是8的倍數的地址處,造成陷阱(更正式地說,UB可能發生任何事情)。

+0

注意,「在實踐中的安全」是不正確的,因爲現代的編譯器優化積極基於任何一種UB的。 – 2013-12-22 18:18:23

+0

也值得一提的對齊和訪問。 –

+0

+1尼斯交代 – Freedom911

2

因爲double指針的大小是不一樣的一個int指針,如果你嘗試使用它,你可能會得到一個分段錯誤。它們不一定是兼容的類型。


您可以嘗試投射pi2指出的值。

void fun(int*pi) 
{ 
    void *pv = pi; 
    int *pi2 = static_cast<int*>(pv); 
    double d = static_cast<double>(*pi2); 
    std::cout << d; // 42 
} 

int main() 
{ 
    int i = 42; 
    fun(&i); 
}