C ++中右移的未定义行为

时间:2018-10-04 12:16:56

标签: c++ bit-shift

来自cppreference.com:

  

对于无符号a和具有非负值的带符号a,其值   a >> b是a / 2 b 的整数部分。对于负a,a的值>>   b是实现定义的(在大多数实现中,   算术右移,以便结果保持负数。)

     

无论如何,如果右操作数的值为负或为   大于或等于提升后的左操作数中的位数,   行为是不确定的。

如果右操作数大于或等于提升后的左操作数的位数,为什么会有不确定的行为?
在我看来,结果应为0(至少对于无符号/正整数)...

尤其是对于g ++(版本4.8.4,Ubuntu):

unsigned int x = 1;
cout << (x >> 16 >> 16) << " " << (x >> 32) << endl;

给予:0 1

2 个答案:

答案 0 :(得分:30)

C ++的目标之一是允许“接近硬件”的快速,高效的代码。在大多数硬件上,可以通过单个操作码实现整数右移或左移。麻烦的是,在这种情况下,不同的CPU在位移幅度大于位数的情况下会有不同的行为。

因此,如果C ++强制要求移位操作具有特定的行为,则在为操作码行为不符合所有标准要求的CPU生成代码时,编译器将需要插入检查和逻辑以确保结果符合在所有情况下均为标准配置。除非优化程序可以证明实际上不会发生极端情况,否则几乎所有使用内置移位运算符的情况都将发生这种情况。添加的检查和逻辑可能会降低程序的速度。

答案 1 :(得分:1)

举一个具体的例子,x86将移位计数修整为5位(64位移位为6位),而ARM将修整计数为8位。使用当前的C ++标准,两个CPU的编译器都可以使用单个操作码来实现移位。

如果C ++标准以特定方式定义移位的结果大于操作数长度,则编译器将针对至少一个CPU系列(如果C ++要求的结果与任何一个都不匹配,则可能面向两者)硬件实现(如您建议的行为)必须使用分支来实现每个移位操作,而分支会在CPU操作码不会产生的情况下产生所需的结果。