为什么不同的左移位实现表现出不同的行为?

15 浏览
0 Comments

为什么不同的左移位实现表现出不同的行为?

这个问题已经有答案了:

为什么(1 << 31) >> 31 的结果是-1?[重复]

我的代码的目的是在我的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位的常量。所以我需要将值存储在另一个变量中。有人能告诉我为什么会发生这种情况,以及如何解决它吗?

非常感谢您!

admin 更改状态以发布 2023年5月20日
0
0 Comments

当试图向32位int的标志位进行左移时,OP的代码可能会引发未定义的行为。

E1 << E2的结果是将E1左移E2个位置; 腾空的位将填充零。…如果E1具有带符号类型和非负值,并且E1×2E2在结果类型中是可表示的,则该值为结果值; 否则行为未定义。C11 §6.5.7 4

因此,使用无符号类型可以避免在31个位移的情况下出现不明确的行为。在32位unsigned中移位32+也会出现问题。

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

#include 
#include 
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

0