C 中的
>`) 在移位 32 位元時會產生意外結果? " />
右移運算子的意外行為(1 >> 32)
在程式設計領域,通常使用右移運算子(>>)執行按位元運算,特別是將整數除以2 的冪。 int a。 返回a>>b; } int bar(uint64_t a, int b) { 返回a>>b; } int main() { std::cout > 32: " > 32) > (int)32: " > (int)32)
int foo(int a, int b) {
return a >> b;
}
int bar(uint64_t a, int b) {
return a >> b;
}
int main() {
std::cout > 32: " > 32) > (int)32: " > (int)32) foo(1, 32): 1 // Should be 0
欄(1, 32): 0
1>>32:0
(int)1 >> (int)32: 0這些結果背後的基本原理在於 CPU 和編譯器的內部運作原理。 foo(1, 32): 1 // Should be 0
bar(1, 32): 0
1 >> 32: 0
(int)1 >> (int)32: 0
foo() 函數的行為
在foo()函數中,移位操作是在沒有強制轉換的情況下執行的,導致CPU執行邏輯右移。在許多架構上,邏輯右移被實作為 a >> (b % 32),有效地忽略 b 的高位。因此,foo(1, 32) 結果為 1 >> (32 % 32),其計算結果為 1 >> 0,產生 1。
為什麼轉換為 64 位元整數很重要?
在bar()函數中,提供了一個64位元無符號整數,確保結果保證為0,因為b(32)小於運算元中的位數(64 )。然而,當 b 更改為 64 時,結果變得不可預測,並且可能仍會產生 1。
編譯器最佳化
在 1 >> 32 且 (int )1 >> (int)32,編譯器在編譯時最佳化這些常數表達式。此標準指定了右移的未定義行為,其中計數為負數或大於或等於操作數的長度。由於 32 超出了操作數的長度,編譯器無法確定結果並輸出 0 作為安全後備。
CPU-Specific Behavior
右移的實現不同 CPU 的操作可能有所不同。在 x86/x86-64 架構上,邏輯右移其實是 a >> (b % 32 或 64),取決於模式。然而,在 ARM 處理器上,右移運算保證大於或等於 32 的移位為零。
結論
使用右移運算子時,這一點至關重要考慮潛在的未定義行為,特別是當移位計數超過操作數的長度時。轉換為更廣泛的整數類型(例如 64 位元整數)可以確保不同 CPU 和編譯器之間的結果一致。
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3