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

时间:2013-09-20 13:39:36

标签: c++ gcc assembly standards undefined-behavior

我刚检查了 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针对代码段提供以下警告,res67108863

  

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

我还检查了GCC发出的汇编代码。它只调用SHRL和SHRL的英特尔指令文档,res不是零。

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

2 个答案:

答案 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(我认为),它可能会给你零。