右移运算符的有趣行为
右移运算符 (>>) 在处理较大的右移值时表现出特殊的行为。考虑以下程序:
<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 }
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中文网其他相关文章!