C中的按位移位

时间:2017-10-16 11:24:57

标签: c gcc bit-manipulation bit-shift

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

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

输出

1
0

代码在Ubuntu 16.04(Xenial Xerus)上运行,我使用gcc -m32 a.c和GCC版本5.4.0进行编译。

我已经阅读了一些帖子,其中解释了为什么a<<b输出1,但我不明白为什么1<<32会导致0.我的意思是,a<<b之间有什么区别?和1<<32

4 个答案:

答案 0 :(得分:6)

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

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

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

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

答案 1 :(得分:3)

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

C11§6.5.7按位移位运算符

第3段:

  

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

第4段:

  

E1 << E2的结果是E1左移E2位位置;腾空   位用零填充。如果E1具有无符号类型,则值为   结果是E1 × 2E2,比最大值减少了一个模数   在结果类型中可表示。如果E1具有签名类型,   非负值,E1 × 2E2可在结果类型中表示,   那就是结果价值;否则,行为是   未定义。

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

海湾合作委员会产生警告:

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

答案 2 :(得分:0)

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

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

如果移动值> gt = =次数,则结果未定义。

答案 3 :(得分:0)

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