我刚检查了 C ++ 标准。以下代码似乎不应该是undefined behavior:
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针对代码段提供以下警告,res
为67108863
:
警告:右移计数> =类型宽度
我还检查了GCC发出的汇编代码。它只调用SHRL
和SHRL的英特尔指令文档,res
不是零。
那么这是否意味着GCC没有在英特尔平台上实现标准行为?
答案 0 :(得分:40)
段落 1 中的5.8
Shift运算符中的draft C++ standard表示(强调我的):
结果的类型是提升的左操作数的类型。 如果右操作数为负数,或大于或等于提升的左操作数的位长度,则行为未定义。
因此,如果 unsigned int 为32 bits
或更少,那么这是未定义的,这正是gcc
给你的警告。
答案 1 :(得分:17)
准确解释发生了什么:
编译器将34
加载到寄存器中,然后将常量加载到另一个寄存器中,并使用这两个寄存器执行右移操作。 x86处理器对移位值执行“shiftcount%bits”,这意味着您可以向右移2位。
由于0x0FFFFFFF(十进制268435455)除以4 = 67108863,这就是你看到的结果。
如果您有不同的处理器,例如PowerPC(我认为),它可能会给你零。