为什么不同的左移位实现表现出不同的行为?
为什么不同的左移位实现表现出不同的行为?
这个问题已经有答案了:
我的代码的目的是在我的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日
当试图向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