2010-02-05 89 views
46

據我所知,reinterpret_cast是危險的,我只是這樣做來測試它。我有以下代碼:爲什麼不能編譯reinterpret_cast?

int x = 0; 
double y = reinterpret_cast<double>(x); 

當我試圖編譯程序,它給了我一個錯誤說

invalid cast from type 'float' to type 'double 

這是怎麼回事?我以爲reinterpret_cast是你可以用來將蘋果轉換成潛艇的流氓演員,爲什麼這個簡單的演員不能編譯?

+0

我從來沒有在C++中試過這個,所以我只是猜測。它是否工作,如果你投的浮動?難道不是這兩種類型的位長不同? – 2010-02-05 06:13:19

+0

「'reinterpret_cast (x)'」你預計這個表達要做什麼? – curiousguy 2012-07-25 15:58:08

+2

int是32位。雙是64位。這可能是問題。你可以檢查一下嗎? – 2012-09-23 16:27:37

回答

34

通過由投返回的值賦給ÿ你並沒有真正投入價值x,你正在轉換它。也就是說,y不指向x並假裝它指向一個浮點數。轉換構造一個新的值float,並從x分配值。有幾種方法可以做到在C++這種轉換,其中:

int main() 
{ 
    int x = 42; 
    float f = static_cast<float>(x); 
    float f2 = (float)x; 
    float f3 = float(x); 
    float f4 = x; 
    return 0; 
} 

唯一的區別是最後一個(隱式轉換),將產生一個編譯器上更高的警告級別的診斷。但他們都在功能上做同樣的事情 - 在很多情況下,實際上是一樣的東西,在相同的機器代碼。

現在,如果你真的想假裝x是float,那麼你真的要投x,這樣做:

#include <iostream> 
using namespace std; 

int main() 
{ 
    int x = 42; 
    float* pf = reinterpret_cast<float*>(&x); 
    (*pf)++; 
    cout << *pf; 
    return 0; 
} 

你可以看到有多危險,這是。實際上,當我在我的機器上運行這個輸出時,輸出是1,這絕對不是42 + 1。

+0

will(float)x返回42或某些不相關double的二進制表示。我認爲這個人意味着重新解釋,那就是他想要的。 – 2012-09-23 16:26:35

+0

'(float)x'將執行轉換,而不是轉換。 – 2012-09-23 22:09:31

+0

您的代碼下面是嚴格的鋸齒違規,因此具有未定義的行爲。 – 2017-10-25 23:41:36

1

reinterpret_cast最適合用於指針。所以指向一個對象的指針可以變成一個「潛艇」。

msdn

reinterpret_cast運算符可用於轉化如char *到 INT *,或* One_class到 Unrelated_class *,這是固有 不安全 。

一個的reinterpret_cast 的結果不能安全地用於任何 不是被轉換回其原來 其他類型。其他用途在 最好,不便攜。

0

將int投射到double不需要投射。編譯器將隱含地執行分配。

reinterpret_cast與指針和引用一起使用,例如將int *轉換爲double *

7

如果你想你的int到一個double的代表性位轉換,你需要轉換地址不是值。您還必須確保尺寸匹配:

uint64_t x = 0x4045000000000000; 
double y = *reinterpret_cast<double *>(&x); 
0

這很有趣。也許它在從int到float的轉換之前進行隱式轉換,然後再嘗試轉換爲double。 int和float類型的字節大小相同(當然取決於你的系統)。

3

編譯器拒絕你寫的廢話,因爲intdouble可能是具有不同大小的對象。你可以達到同樣的效果這樣,雖然它肯定是危險的:

int x = 0; 
double y = *reinterpret_cast<double*>(&x); 

這是潛在的危險,因爲如果xy是不同勢的大小(假設int是四個字節,並將double是八個字節),那麼你的時候在解引用的&x八個字節的內存來填補y您將訪問四個字節的x和四個字節的......在記憶最終會發生什麼(的y可能啓動,或垃圾,或別的東西完全。)

如果你想轉換一個intege r加倍,使用static_cast,它將執行轉換。

如果您要訪問的x的位模式,投給了一些方便的指針類型(比如,byte*),並獲得高達sizeof(int)/sizeof(byte)

byte* p = reinterpret_cast<byte*>(&x); 
for (size_t i = 0; i < sizeof(int); i++) { 
    // do something with p[i] 
} 
+2

不是編譯器拒絕它的原因,但關於字體大小的討論是有價值的。 – 2010-02-05 09:06:32

11

reinterpret_cast不是一般演員。根據C++ 03規範第5.2.10.1節:

下面列出了可以使用reinterpret_cast明確執行的轉換。沒有其他轉換可以使用reinterpret_cast顯式執行。

並沒有列出什麼,說明整數和浮點類型之間的轉換(或整型之間,即使這是非法的reinterpret_cast<long>(int(3));

2

重釋投可以讓你重新詮釋的內存塊爲不同類型的。這必須在指針或引用進行:

int x = 1; 
float & f = reinterpret_cast<float&>(x); 
assert(static_cast<float>(x) != f); // !! 

的另一件事是,它實際上是一個相當危險的演員,這不僅是因爲陌生值出來的結果,或斷言上面沒有失敗,但是因爲如果類型的大小不同,並且您從「源」到「目標」類型重新解釋,則對重新解釋的引用/指針的任何操作都將訪問sizeof(destination)字節。如果sizeof(destination)>sizeof(source)然後,將步驟超出了實際可變存儲器,有可能殺死你的應用程序或overwritting比源或目的地以外的其他變量:

struct test { 
    int x; 
    int y; 
}; 
test t = { 10, 20 }; 
double & d = reinterpret_cast<double&>(t.x); 
d = 1.0/3.0; 
assert(t.x != 10); // most probably at least. 
asswet(t.y != 20); 
34

在C++ reinterpret_cast只能執行一組特定的轉換,在明確列出語言規範。簡而言之,reinterpret_cast只能執行指針到指針的轉換和參考到引用的轉換(加上指針到整數和整數到指針的轉換)。這與演員的名字所表達的意圖是一致的:它意在用於指針/參考重新解釋。

你試圖做的不是重新解釋。如果你想重新詮釋的intdouble你必須將其轉換爲引用類型

double y = reinterpret_cast<double&>(x); 

雖然相當於基於指針的重新解釋可能是更明確的

double y = *reinterpret_cast<double*>(&x); // same as above 

不過請注意,而reinterpret_cast可以轉換引用/指針類型,實際嘗試通過結果引用/指針讀取數據會產生未定義的行爲。

在任何情況下這一點,當然也沒有多大意義的平臺上int和不同尺寸的double(因爲在大double情況下,你會讀超出x佔用的內存)。

所以,最後,這一切都歸結爲你想要達到的目標。記憶重新解釋?往上看。某種更有意義的intdouble轉換?如果是這樣,reinterpret_cast不會幫你在這裏。

+0

'reinterpret_cast只能執行指針到指針的轉換和引用到引用的轉換(加上指針到整數和整數到指針的轉換)''這個問題變得平坦了,可以被接受爲答案。 – 2017-07-08 15:09:17