为什么我用C语言做按位右移时结果不一样?

问题描述

我写了下面的代码来理解按位右移操作,

unsigned long a = 0;
unsigned long b = 0xFFFFFFFF;
a = ~a;                   // Now a is equal to b
a = a >> 1; 
b = b >> 1; 
printf("a = %x\n",a);    // result: a = 0xFFFFFFFF
printf("b = %x\n",b);    // result: b = 0x7FFFFFFF

我认为在右移操作之前a和b都等于0xFFFFFFFF,然后在右移之后结果应该是相同的。但结果表明

  • a = 0xFFFFFFFF
  • b = 0x7FFFFFFF

好像a的MSB为1,b的MSB为0。为什么会出现这种差异?

解决方法

如果您修正错误的说明符并添加一些额外的打印输出,您会发现您的假设是错误的:

#include <stdio.h>

int main(void) {
    unsigned long a = 0;
    unsigned long b = 0xFFFFFFFF;
    printf("a = %lx\n",a);   
    printf("b = %lx\n",b);    
    a = ~a;                   // now a is equal to b

    printf("a == b? %s\n",a == b ? "Yes" : "No");

    printf("a = %lx\n",b);   
    a = a >> 1; 
    b = b >> 1; 
    printf("a = %lx\n",a);    // result: a = 0xFFFFFFFF
    printf("b = %lx\n",b);    // result: b = 0x7FFFFFFF
}

输出:

$ ./a.out 
a = 0
b = ffffffff
a == b? No
a = ffffffffffffffff
b = ffffffff
a = 7fffffffffffffff
b = 7fffffff

记得用 -Wall -Wextra 编译以捕获这样的错误。

解决方案:更改为:unsigned long b = -1; 另一种解决方案:包括 limits.h 并使用 ULONG_MAX

值得注意的是,long 没有固定的宽度。如果您想要固定宽度,请使用 uint32_t 之类的类型。