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

Zij*_*gWu 32 c++ assembly standards gcc undefined-behavior

我刚检查了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
Run Code Online (Sandbox Code Playgroud)

并从标准:

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

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

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

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

我还检查了GCC发出的汇编代码.它只是调用SHRL,而SHRL的英特尔指令文件res不是ZERO.

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

Sha*_*our 40

草案C++标准在部分5.8 移位运算符在第1说(重点矿山):

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

因此,如果unsigned int32 bits或更小,那么这是未定义的,这正是gcc给你的警告.

  • @Zaibis:是的,GCC能够编译C++.一个常见的误解是GCC(仅)是一个C编译器,或者G ++是一个不同的编译器. (8认同)

Mat*_*son 17

要准确解释发生了什么:编译器将加载34到寄存器中,然后加载到另一个寄存器中的常量,并使用这两个寄存器执行右移操作.x86处理器对移位值执行"shiftcount%bits",这意味着您的右移为2.

由于0x0FFFFFFF(十进制268435455)除以4 = 67108863,这就是你看到的结果.

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

  • @Zaibis GCC 是一个可移植编译器,没有理由禁用 GCC 内部的代码,当它为 PowerPC 发出代码时,它会警告偏移量太大。但我可以向您保证,PowerPC 处理器确实有几个额外的晶体管,允许右移汇编指令在移位 34 时产生预期结果。 (2认同)