2013-01-31 59 views
6

這是我想做的事:爲什麼我不能reinterpret_cast uint int?

const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);

哪裏randomUintNumber是uint64_t類型。

該錯誤是(2010 MSVC):

錯誤C2440: '的reinterpret_cast':不能從 'const的uint64_t中' 轉換 '的int64_t' 1>轉換是有效的標準轉換, 其可以是隱式執行或使用static_cast,C-style 演員表或功能風格演員表

爲什麼不編譯?這兩種類型的位長相同,是不是reinterpret_cast的目的是?

+0

如果你可以列出你得到的錯誤,我們可以更容易地說_why_它不能編譯。 –

+0

@JoachimPileborg:我的不好,擴大了這個問題。 –

回答

19

因爲這不是reinterpret_cast的用途。使用reinterpret_cast的所有允許的轉換都涉及指針或引用,但整數或枚舉類型可以是reinterpret_cast。這全部在標準[expr.reinterpret.cast]中定義。

我不能確定你想在這裏實現什麼,但如果你想randomIntNumber具有相同的價值randomUintNumber,然後做

const int64_t randomIntNumber = randomUintNumber; 

如果在編譯器警告的結果,或者如果你只是想更加明確,那麼:

const int64_t randomIntNumber = static_cast<int64_t>(randomUintNumber); 

投的結果具有相同的值作爲輸入,如果randomUintNumber小於2 。否則結果是實現定義的,但我期望所有已知的具有int64_t的實現都將它定義爲做明顯的事情:結果等效於輸入模2 。


如果你想randomIntNumber具有相同的位模式爲randomUintNumber,那麼你可以這樣做:

int64_t tmp; 
std::memcpy(&tmp, &randomUintNumber, sizeof(tmp)); 
const int64_t randomIntNumber = tmp; 

由於int64_t保證使用二進制補碼錶示,你會希望那該實現定義static_castuint64_t的超出範圍的值具有相同的結果。但在標準AFAIK中實際上並未得到保證。

即使randomUintNumber是編譯時常量,不幸的是這裏的randomIntNumber而不是的編譯時常量。但是,那麼「隨機」是一個編譯時常量? ;-)

如果您需要解決的是,和你不信任的實施是明智的有關轉換超出範圍的無符號值符號類型,則這樣的事:

const int64_t randomIntNumber = 
    randomUintNumber <= INT64_MAX ? 
     (int64_t) randomUintNumber : 
     (int64_t) (randomUintNumber - INT64_MAX - 1) + INT64_MIN; 

現在,我贊成在可能的情況下編寫真正可移植的代碼,但即使如此,我認爲這也偏執於偏執狂。


順便說一句,你也許會這樣寫:

const int64_t randomIntNumber = reinterpret_cast<int64_t&>(randomUintNumber); 

或等價:

const int64_t randomIntNumber = *reinterpret_cast<int64_t*>(&randomUintNumber); 

這倒不保證工作,因爲儘管他們存在int64_tuint64_t保證是有符號類型和相同大小的無符號類型,它們實際上並不保證是標準整數類型的有符號和無符號版本。因此,無論此代碼是否違反嚴格的別名,它都是特定於實現的。違反嚴格別名的代碼具有未定義的行爲。下面確實違反嚴格別名,並確定規定,在randomUintNumber位模式是long long值的有效表示:

unsigned long long x = 0; 
const long long y = reinterpret_cast<long long &>(x); 

因此,對實現中int64_tuint64_tlong longunsigned long long的typedef ,那我的reinterpret_cast就OK了。就像實現定義的將超出範圍的值轉換爲帶符號的類型一樣,您希望期望實現要做的明智事情是使它們對應於signed/unsigned類型。所以就像static_cast和隱式轉換一樣,您希望它可以在任何明智的實現中工作,但實際上並未得到保證。

+0

感謝您的詳細解答! –

2

在這些情況下使用static_cast。我認爲語言設計師們全智慧地決定認爲它不足以保證reinterpret_cast「不夠安全」。

3

不,它不是。 reinterpret_cast通常旨在將現有的存儲位重新解釋爲與現有存儲位不同的類型。很多這些解釋都是依賴於實現的,並且標準列出了可以用reinterpret_cast(主要在不同的指針/參考類型之間進行鑄造)完成的特定(可以在此處引用很長的)列表,但是說:

使用 reinterpret_cast可以明確地執行其他轉換。

就您而言,您可能需要轉換類型,而不是重新解釋現有存儲。爲此,請使用static_cast

+0

但重新解釋正是我想要的!我不確定static_cast(或C-cast)會產生所需的結果,必須首先刷新我的記憶。 –

+1

@VioletGiraffe:如果你想重新解釋某個存儲爲另一種類型,那麼你應該重新解釋一個指向該存儲的指針。請注意,儘管您正在進入IB/UB地區,尤其是在您取消結果的情況下。 – PlasmaHH

+0

我怎麼能忘記......這正是我最近一次遇到它時(我的目標類型的指針並取消引用它)解決了這個問題。 IB/UB究竟在哪裏出現? –

0

爲什麼不編譯?

因爲這兩種類型都不是指針。

兩種類型具有相同的位長,

爲什麼會是怎麼回事?如果他們是指針,或許它們指向相同大小的東西會很重要,但它們不是指針。

是不是reinterpret_cast的目的是?

不,reinterpret_cast是用於指針轉換。你可以通過在劇組裏面放置&以及在其外部放置*來做你想做的事。這就是重新演繹演員的原因。

+0

位長很重要,因爲顯然,您會遇到問題逐位重新解釋不同長度的類型。 –

+0

這是對'reinterpret_cast'的常見誤解。從概念上講,它並不是按照重新解釋(儘管在'平常'的常見平臺上)。例如,C++標準(5.2.10)指出,使用reinterpret_cast,可以將「指針顯式轉換爲足夠大的任何整數類型來保存它。」 - 包括*更大*的整數類型。而且,它明確表示它「可能會或可能不會產生與原始值不同的表示」。 –

+0

@VioletGiraffe使用'reinterpret_cast'的結果時,指向(或引用)對象的位長很重要。這些指針本身的位長是不相關的:即使當char *和int *具有不同的大小(就像它們有時在舊機器上那樣),你也可以在'char *'和'int *'之間'reinterpret_cast'。 –

1

從C++ 11標準(N3376)5.2.10.1:可以顯式使用的reinterpret_cast進行

換算在下面列出。沒有 其他轉換可以使用reinterpret_cast顯式執行。

如果類型相同,只允許從整型到整型的轉換。

其他涉及指針。

1

reinterpret_cast用於將對象的存儲重新解釋爲不同的對象。如果你不想通過標準的措辭,你可以找到所有reinterpret_cast可以做here。通常你可以記住你必須使用指針類型。

所以,如果你真的想重新詮釋用於您uint64_tint64_t,然後做到這一點位:

int64_t randomIntNumber = reinterpret_cast<int64_t&> (randomUintNumber); 

但是如果你只是想轉換對象,如果有可能保留它的價值...只需執行編譯器建議的內容並使用static_cast代替。

+0

謝謝,我不知道'reinterpret_cast'是它的用途有限。感謝您展示黑客:) –

相關問題