为什么我在左位移的不同实现中有这种不同的行为?

why do I have this different behavior in different implementations of left bit-shift?

我的代码的目的是在我的 int(32 位)表示的右侧创建一个包含 n 个零的掩码。我的方法是首先将负数存储在一个变量中,然后将它向左移动 n 个空格,以便在右边有 n 个零。代码如下:

int mask(int n){
  int neg1=(1<<31)>>31;
  int mask=neg1<<n;
  return mask;
}

尽管如此,当 n 为 32 时,我想获得值 0x0,但我得到的是 0xffffffff (neg1)。当我转移到变量时会发生这种情况。但是当我转换到常量本身时,它就像一个魅力。新代码将是:

mask=0xffffffff<<n;

尽管如此,我不允许使用超过 8 位的常量。所以我需要存储在另一个变量中的值。谁能告诉我为什么会这样,我该如何解决?

非常感谢!

OP 的代码在尝试左移到 32 位 int 的符号位时调用未定义的行为。

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. ... 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. C11 §6.5.7 4

而是使用无符号类型来避免移位 31 时定义错误的行为。在 32 位 unsigned 上移位 32+ 也将是一个问题。

一种简单的方法使用更宽的类型。

#include <stdio.h>
#include <inttypes.h>

uint32_t mask32(int n) {
  return 0 - (1ull << n);
}

int main(void) {
  for (int i=0; i<=32; i++) {
    printf("%2d %lX\n", i, (unsigned long) mask32(i));
  }
}

输出

 0 FFFFFFFF
 1 FFFFFFFE
 2 FFFFFFFC
 ...
29 E0000000
30 C0000000
31 80000000
32 0