在GCC下,如果<<
,则以下代码始终返回num1s == 0
的左操作数:
0xFFFFFFFFu << (32-num1s);
在阅读Why doesn't left bit-shift, "<<", for 32-bit integers work as expected when used more than 32 times?和David Heffernan引用的标准后,似乎左操作数是无符号,它是一个已定义的操作。只有当E1(左操作数)具有有符号类型和非负值时才会导致未定义的行为。
任何人都可以解释标准是否明确说明如果移位的数量大于类型所包含的位数,那么它是未定义的行为?
答案 0 :(得分:4)
§5.8转换运算符
结果的类型是提升的左操作数的类型。 如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义。
E1 << E2
的值为E1
左移E2
位位置;空位是零填充的。如果E1
具有无符号类型,则结果的值为E1 × 2E2
,减去模数比结果类型中可表示的最大值减1。否则,如果E1
具有签名类型和非负值,并且E1×2E2
在结果类型中可表示,那么这就是结果值;否则,行为未定义。
答案 1 :(得分:1)
CoryKramer已经回答了为什么它是标准的未定义行为。
我会尝试在实际情况中证明它是如何运作的。 C ++编译器通常将32位整数的<<
和>>
运算符实现为汇编程序指令而不检查操作数范围。这意味着结果取决于移位指令的特定于处理器的实现。
例如,针对32位SHL / SHR / SAL / SAL指令的英特尔处理器规范说:
目标操作数可以是寄存器或内存位置。该 count操作数可以是立即值或寄存器CL。伯爵是 屏蔽为5位,将计数范围限制为0到31。
这意味着a << b
在英特尔处理器上变为a << (b & 0x1f)
。因此,移位32位意味着没有移位。
但你不应该依赖这些信息!编译器还可以优化代码并使用向量指令实现移位运算符。在这种情况下,即使按处理器规范也未指定行为。