2014-02-13 79 views
8

以下代碼在C++ 11中是否合法?在C++ 11中縮小轉換次數:轉換後的實際值是多少?

int16_t x {0xaabb}; 
int64_t xxxx {0xaaaabbbbccccdddd}; 

該代碼來自「The C++ Programming Language」第4版(第150頁)。

正如我們所知,收縮轉換是不允許的列表初始化,以及縮小轉換標準的定義中,我們有:

收縮轉換是隱式轉換
- [...]
- 從整數類型或非範圍枚舉類型轉換爲無法表示原始類型的所有值的整數類型,除非源代碼是常量表達式並且轉換後的實際值將適合目標類型並將生成轉換回原始類型時的原始值。

檢查縮小轉換針對示例代碼的規則中,我認爲該示例代碼是非法的,因爲0xaabb0xaaaabbbbccccdddd不能在int16_tint64_t分別表示。那是對的嗎?

但我不太明白措辭「除了源是一個常量表達式和轉換後的實際值將適合目標類型,並將轉換回原始類型時產生原始值」 。我想知道轉換後的實際值不能在中適合目標類型。由於整數類型之間的轉換總是有效的(儘管在目標類型已簽名且源值不能在目標類型中表示的情況下是實現定義的,但它不是未定義的行爲),總是這樣的:「值轉換後是否符合目標類型「?從這個角度來看,我開始質疑我對示例代碼縮小轉換的判斷。如果是這樣的話,爲什麼標準在某種情況下總是把事情做成真實的?爲什麼不只是說「除了源是一個常量表達式,轉換後的實際值在轉換回原始類型時會產生原始值」?

有人可以幫我澄清一下嗎?謝謝!

+1

我認爲這個問題來自於'0xaabb'可以被認爲是一個「正數」常量,但是當它被分配給一個'int16_t'時,它就變成了一個負數。嗯,我剛剛回復了一個不再在這裏的評論,但我會留下這個,因爲它可能會澄清問題。 – icabod

+0

您是否可以改進標題,以便在問題列表中將此問題與其他人區分開來? –

+0

經驗上說,它應該是合法的,因爲GCC會發出警告(所以編譯器明確知道這個問題),但它不會發出錯誤。如果它確實是非法的,那麼編譯應該會發生錯誤(而不是警告)。 – Damon

回答

5

這是標準中的缺陷,請參閱CWG issue 1449。文本已經被從整數型或無作用域枚舉類型爲整數類型,它可以不表示原始類型的所有值改變爲

,除了其中所述源是一個常量表達式,其值後積分優惠將適合進入目標類型

注:事件的狀態,DRWP,意味着正式的標準尚未改變,並且可以由一個參數,至少你的int64_t例子是C++ 11的法律。不過,編譯器已經實施了新的規則,因爲這已經是原來措辭的意圖。

+0

非常感謝您的信息。我仍然不清楚「適合哪個」和「可以用'來表示」之間的區別。如果它們意味着同樣的事情,那麼'int64_t'示例應該縮小轉換範圍。如果它們不一樣,那麼究竟有什麼區別? – goodbyeera

+0

@goodbyeera除非我誤讀,否則它們意味着同樣的事情,所以'int16_t'和'int64_t'例子都是基於新的措辭的縮小轉換。 – hvd

0

讓我們看看該值是如何轉換爲符號整數:

4。7/3如果目標類型是有符號的,如果目標類型可以用目標類型(和位域寬度)表示,則值不變。否則,該值是實現定義的

所以這些轉換給出了實現定義的值。一個明智的實現將定義轉換,爲該位模式提供相應的負值,這符合目標類型。

所以問題是,轉換回文字的類型是否保留了值?這取決於實現定義的文字類型的大小。如果int恰好有16位,則第一個將保留該值,但如果它較大(在這種情況下0xaabb將被簽名,且轉換將給出負值)則該值不會保留。同樣,如果int正好有64位,或者int更小,long long恰好有64位,則第二個將保留該值。

結論:這取決於。在32位int和64位long long的典型當前平臺上,第一個將縮小,而第二個不會。 GCC同意,並以-pedantic發出第一個警告。