2017-10-06 88 views
-2

我正嘗試在C++中使用位數組數據結構。這是簡單的好奇心,但我應該怎麼解釋:爲什麼移位運算符似乎循環64位整數?

uint64_t a = 1; 
uint64_t b = a << 1; 

cout << (a == (a << 64)) << endl; // get 1 
cout << (a == (b << 63)) << endl; // get 0 

似乎是一個< < x是x >= 64,但墊用零x < 64。我錯了嗎 ?

如果不是,那麼解釋是什麼?我認爲64位整數不是自然循環的。

回答

5

根據[expr.shift]:

的行爲是不確定如果將右操作數是負的,或以位爲促進左操作數的比大於或等於所述長度。

因此,這是未定義的行爲:

uint64_t a = 1; 
a << 64; 
+0

你能解決這個問題的另一半,'(a << 1)<< 63'的行爲嗎? –

+0

@Robᵩ沒有什麼可以解釋的:這是完美的預期。我所理解的問題的精神在於:爲什麼在一次操作中將64位移位與在兩位操作中不同?_ – YSC

1

如YSC說明的那樣,在一個操作中的比類型尺寸更移是未定義的行爲;這個規則來自將位移運算符直接映射到機器代碼指令的願望,在這種情況下,處理器具有不同的行爲。

例如,在x86上,SHL指令將屏蔽移位量爲63(當在64位寄存器上操作時),這可能是您看到a<<64保持爲1的原因(因爲64 & 63 == 0,因此它實際上是一個no- OP)。

請注意,這僅僅是一個簡單的例子(通常情況下,禁用優化,或啓用優化但移位量未知,因此當移位映射到底層平臺移位操作碼時)通常很好地適用。當用常量移動常量時,編譯器可以以更高的精度傳播值並執行內部算法,或者即使在一般情況下,也可以發出在大於數據類型的寄存器中工作並在最後截斷的代碼(例如,合法將一個uint32_t的移位映射到完整的64位寄存器移位,雖然不是特別聰明),因此在這些不合規格的情況下給出了不同的結果。請記住:未定義的行爲是未定義的,你不能真正期望任何特定的事情發生。

另一方面,在兩個步驟中的操作按預期工作,因爲兩個操作都是定義良好的(它們在右側填充零,在左側填充零)。

+1

這是_why_的一個很好的解釋,它被選爲UB。 +1 – YSC