提问者:小点点

如果计数大于类型的宽度,右移位是否为未定义行为?


我刚刚检查了C++标准。下面的代码似乎不应该是未定义的行为:

unsigned int val = 0x0FFFFFFF;
unsigned int res = val >> 34;  // res should be 0 by C++ standard,
                               // but GCC gives warning and res is 67108863

并从标准:

E1>>的值;E2是E1右移的E2位位置。如果E1具有无符号类型,或者如果E1具有有符号类型且具有非负值,则结果的值是E1/2^E2的商的整数部分。如果E1具有带符号类型和负值,则结果值是实现定义的。

根据标准,由于34不是负数,变量res将为0。

GCC为代码段提供以下警告,且res67108863:

警告:右移位计数>=类型宽度

我还检查了GCC发出的汇编代码。它只是调用SHRL,而针对SHRL的Intel指令文档,res不是零。

那么这是否意味着GCC没有在Intel平台上实现标准行为呢?


共2个答案

匿名用户

C++标准草案5.8Shift operators(第1段中的移位运算符)说(着重号为mine):

结果的类型是提升的左操作数的类型。如果右操作数为负数,或者大于或等于提升的左操作数的长度(以位为单位),则行为未定义。

因此,如果无符号int是32位或更小,则这是未定义的,这正是gcc给您的警告。

匿名用户

为了确切地解释所发生的情况:编译器将把34加载到一个寄存器中,然后把常数加载到另一个寄存器中,并对这两个寄存器执行右移位操作。x86处理器对shift值执行“ShiftCount%bits”,这意味着您将右移2。

由于0x0FFFFFFFFF(268435455十进制)除以4=67108863,这就是您看到的结果。

如果您有一个不同的处理器,例如PowerPC(我认为),它很可能给您零。