C中的按位移位

我得到了一些令我困惑的C代码:

int a = 1; int b = 32; printf("%d\n %d\n", a<<b, 1<<32); 

输出是

 1 0 

代码在Ubuntu 16.04(Xenial Xerus)上运行,我使用GCC版本5.4.0的gcc -m32 ac编译它。

我读过一些post已经解释了为什么a<<b输出1,但我不明白为什么1<<32结果为0.我的意思是, a<<b1<<32之间a<<b什么区别?

将32位int移位32是未定义的行为,因此可以生成任何值作为结果。 在1<<32表达式的情况下,您的C编译器应该警告您。

您看到的两个输出不同的原因是它们由不同的代码路径生成:

  • a << b使用变量,因此它在运行时由编译的代码计算
  • 1<<32是一个常量表达式,因此它在编译时由编译器本身计算

看起来编译的代码按模32执行移位,因此移位32与移位零相同。 然而,编译器本身移位32,将一位丢弃。 编译器可以自由地执行此操作,因为此行为未定义。 因此,该标准不要求任何特定行为,甚至同一程序的各部分之间的一致行为。

a<1<<32未定义的行为 ,因为右操作数等于位数。

C11§6.5.7按位移位算子

第3段:

对每个操作数执行整数提升。 结果的类型是提升的左操作数的类型。 如果右操作数为负数,或者大于或等于左表达式类型中的位数,则结果为undefined。

第4段:

E1 << E2的结果是E1左移E2位位置; 腾出的位用零填充。 如果E1具有无符号类型,则结果的值为E1 × 2E2 ,模数比结果类型中可表示的最大值减1。 如果E1具有有符号类型和非负值,并且在结果类型中可以表示E1 × 2E2 ,那么这就是结果值; 否则, 行为未定义。

因此,如果数字的移位大于整数的大小,则行为是未定义的。

GCC产生警告:

 warning: left shift count >= width of type [-Wshift-count-overflow] printf("%d\n%d",a< 

通过恒定值移位而不是移位b位可以导致在未定义的行为可能优化不存在的规则下的不同行为。 换句话说,移位恒定值可能与移位可变位数的方式不同。 两者都显然是未定义的行为,因此编译器可以随心所欲地处理任何一种情况。 它可以从字面上生成随机数。

转移签名值是危险的,应该避免。

如果int的大小是32位,则1 << 31是依赖于实现的 - 二的补码= -2147483648。 -1 << 31给出相同的结果。

如果将值> =次移位,则结果未定义的位数。