【问题标题】:Why is `int >> 32` not always zero? [duplicate]为什么`int >> 32`不总是零? [复制]
【发布时间】:2015-07-04 04:56:54
【问题描述】:

有人可以解释一下为什么某些 4 字节整数的右 32 位移位可能在 C/C++ 中返回不为零吗?为什么要依赖编译器的-O选项?

例如,此代码在 gcc 4.8.3 中给出 45 和 -O0 和 0 和 -O3 选项:

unsigned int x = 45; // 4 bytes
x = x >> 32;
printf("%u\n", x);

为什么会这样?

【问题讨论】:

    标签: c++ c bit-manipulation shift


    【解决方案1】:

    因为它是未定义的行为:[expr.shift]

    如果右操作数为负数,或者大于或等于提升的左操作数的位长度,则行为未定义。

    至于具体未定义的行为,我想是这样的:

    • 使用-O0,它编译为在机器代码中实际执行右移,并且在某些机器上(例如我相信 x86 就是这样),移位函数在移位 32 时只查看移位量的低 5 位-位字;移位 32 与移位 0 相同。
    • 使用-O3,编译器自己计算常量,然后将0 放入程序中,而不是让它进行计算。

    您可以检查汇编输出,看看我的预测是否正确。

    【讨论】:

    • 我期待第二种行为,但是在我的依赖于这种行为并使用 -O3 标志编译的代码中,我确实有 32 个班次的非零结果。也许是因为编译器执行 -O3 优化不统一。所以,归根结底,你不能依赖这个。正如你所说,它是未定义的。
    • PS:但我认为这是不对的,应该定义:来自左侧的位应该为零。时期。 ——