C 中的位移位

Bitwise shift in 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 -m32 a.c 和 GCC 5.4.0 版编译它。

我看过一些解释为什么 a<<b 输出 1 的帖子,但我不明白为什么 1<<32 结果为 0。我的意思是,[=13 之间有什么区别=] 和 1<<32?

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

C11 §6.5.7 移位运算符

第 3 段:

The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.The result is undefined if the right operand is negative, or greater than or equal to the number of bits in the left expression’s type.

第 4 段:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

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

GCC 生成警告:

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

移动带符号的值是危险的,应该避免。

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

如果您移动值 >= 位数,则结果未定义。

移位一个常量值与移位 b 位可能会导致不同的行为,因为未定义的行为可能会被优化为不存在。换句话说,按恒定值移位可能与按可变位数移位进行优化不同。两者显然都是未定义的行为,因此编译器可以随意处理任何一种情况。它实际上可以生成随机数。

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

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

  • a << b使用变量,所以在运行时由编译代码计算
  • 1<<32是一个常量表达式,所以在编译时由编译器自己计算

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