右移運算子的有趣行為
右移運算子(>>) 在處理較大的右移值時表現出特殊的行為。考慮以下程序:
<code class="c++">#include <iostream> #include <stdint.h> int foo(int a, int b) { return a >> b; } int bar(uint64_t a, int b) { return a >> b; } int main() { std::cout << "foo(1, 32): " << foo(1, 32) << std::endl; std::cout << "bar(1, 32): " << bar(1, 32) << std::endl; std::cout << "1 >> 32: " << (1 >> 32) << std::endl; //warning std::cout << "(int)1 >> (int)32: " << ((int)1 >> (int)32) << std::endl; //warning }</code>
foo(1, 32) 的預期輸出將為 0,但令人驚訝的是,它會傳回 1。這可以歸因於以下原因:
邏輯移位與算術移位
在x86/x86-64 架構上,右移運算子實際上執行邏輯右移,這表示它會填滿空出的空間帶有0 的位,無論左操作數的符號為何。此行為類似於使用>>> b.
編譯器最佳化
在foo(1, 32) 的情況下,值32 被轉換為int,這實際上被截斷為32 位元。由於 int 可以容納的最大值是 231-1,因此右移本質上是一個 >>> (32 % 32),其計算結果為 0。
未定義的行為
相關的C 標準規定,對於計數大於的右移,「行為未定義」大於或等於提升的左操作數的寬度。在這種情況下,1>>都成立。 32、(int)1>> (int)32 的計數大於 32,導致不可預測的結果。
與 bar(1, 32) 的區別
函數 bar 採用 64 位元無符號整數,保證寬度大於 32。因此,bar 中的右移不受未定義行為的影響。
結論
的行為當處理大的移位值時,右移運算子變得不明確。在 x86/x86-64 架構上,執行邏輯右移,而在 ARM 上,可能會使用不同的實作。由於未定義的行為,在可移植程式碼中應避免計數大於或等於操作數寬度的右移結果。
以上是## 為什麼右移位運算子在大移位值時會表現出意外行為?的詳細內容。更多資訊請關注PHP中文網其他相關文章!