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

C++ C+中右移的未定义行为+;,c++,bit-shift,C++,Bit Shift,从cppreference.com: 对于无符号a和具有非负值的有符号a,值为 a>>b是a/2b的整数部分。对于负值a,a的值>> b是实现定义的(在大多数实现中,它执行 算术右移,使结果保持为负数) 在任何情况下,如果右操作数的值为负数或 大于或等于提升后的左操作数中的位数, 该行为未定义 如果右操作数大于或等于提升后的左操作数中的位数,为什么会有未定义的行为? 在我看来,结果应该是0(至少对于无符号/正整数) 特别是使用g++(版本4.8.4,Ubuntu): 无符号整数x=1; CU+>

从cppreference.com:

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

在任何情况下,如果右操作数的值为负数或 大于或等于提升后的左操作数中的位数, 该行为未定义

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

特别是使用g++(版本4.8.4,Ubuntu):

无符号整数x=1;

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


<> P> >如果C++为移位操作指定了特定的行为,则在为其操作码行为不符合所有标准要求的CPU生成代码时,编译器需要插入检查和逻辑以确保结果在所有情况下都是由标准定义的。这需要在几乎所有使用内置移位操作符的情况下发生,除非优化器能够证明这种情况不会发生。添加的检查和逻辑可能会降低程序的速度。

举一个具体的例子,x86将移位计数修剪为5位(6位表示64位移位),而ARM将移位计数修剪为8位。使用当前C++标准,两个CPU的编译器都可以用单个操作码实现移位。
<>如果C++标准以特定的方式定义移位的结果大于操作数长度,编译器至少针对CPU家族中的一个(并且可能两者都是,如果C++所要求的结果与硬件实现不匹配,就像您建议的行为)必须使用分支来实现每个轮班操作,这些分支将产生CPU操作码无法产生的所需结果。

请参阅:-实际上这不是一个重复的问题,但肯定会解释这是未定义的行为,以及原因。简短版本:现代处理器中的移位指令的移位量通常不会超过寄存器位宽度。一些右移汇编指令的第二个操作数只有5位。32的前5位是0,因此在某些汇编语言中有1>>0。您可以自己制作:
无符号整数右移位(无符号整数x,整数移位量){if(移位量>=std::numeric\u limits::digits)返回0;返回x>>shift\u amount;}
注意到检查大小的额外工作了吗?这就是为什么
>
本身不能做到这一点。至少在
x86
上,移位指令只考虑/屏蔽较低的
5
位,即它基本上是
x>(num%32)
(与
Long read相同,但如果您对未定义的行为,特别是其背后的动机感到好奇,则非常有趣。这并不能解释为什么它不是实现定义的行为,而不是完全未定义的行为。这也允许“接近硬件”implementations.Implementation-defined意味着编译器要处理它。如果我们只是把东西传递给CPU,它就不是实现定义的。编译器的制造商不知道会发生什么。你可以用指令检查特定的CPU会做什么,并列出哪个CPU会发生什么。但它仍然不会被实现定义了移位,它将是环境定义的。@Ruslan实现定义的行为让编译器从一组选项中进行选择。例如,如果移位的值是实现定义的,则CPU将被禁止将其作为错误捕获。@CortAmmon对,如果值是实现定义的。但是行为呢?它可以也可以定义实现,然后允许捕获,但需要记录并保持一致,这与UB不同,UB可能导致逻辑悖论或诸如此类的情况。然而,编译器已经必须意识到CPU的功能。
unsigned int x = 1;
cout << (x >> 16 >> 16) << " " << (x >> 32) << endl;