在 C 中链接移位运算符后出现意外结果

Unexpected result after chaining bit-shift operators in C

我不明白为什么链接移位操作返回的结果与不链接它们的结果不同。

#include <stdio.h>

void bit_manip_func(unsigned char byte)
{
    unsigned char chain = (((byte >> 3) << 7) >> 3);
    printf("%d\n", chain); //this prints 144

    unsigned char o1 = byte >> 3;
    unsigned char o2 = o1 << 7;
    unsigned char o3 = o2 >> 3;
    printf("%d\n", o3); //this prints 16 as expected
}

int main()
{
    //expecting both printf's to print
    //the same value (16).
    bit_manip_func(73);
    return 0;
}

我希望 printf 调用都打印出 16,因为二进制中的 73 是 0100 1001。在应用 byte >> 3 之后我应该得到 0000 1001,在 (byte >> 3) << 7 之后结果应该是 1000 0000,在 (((byte >> 3) << 7) >> 3) 之后结果应该是 0001 0000,当然是 16。实际发生了什么?

unsigned char chain = (((byte >> 3) << 7) >> 3);

((byte >> 3) << 7) 被提升为 int,然后它在 int

上执行 >> 3

包装成 unsigned char (mod 256) 你得到 ((73 >> 3) << 7) >> 3) % 256 = 144

使用强制转换:

unsigned char chain = ((unsigned char)((byte >> 3) << 7) >> 3);

运算符 >> 和 << 对其操作数执行整数提升。因此,当与任一运算符一起使用时,类型 unsigned char 被提升为 int。

在下面一行中,变量byte被提升为int类型,然后三个操作都在这个类型上进行:

unsigned char chain = (((byte >> 3) << 7) >> 3);

因此保留设置为 1 的最左边的位:

01001001 => 01001 => 010010000000 => 010010000 
 ^           ^        ^               ^

在下面的代码中,变量被提升为 int 类型,但在每次操作之后,具有 int 类型的结果被分配给一个 unsigned char 并因此换行(最高有效位被删除),
因为 unsigned char 的范围在您的平台上是 [ 0 , 2^8-1 ]。

unsigned char o1 = byte >> 3;
unsigned char o2 = o1 << 7;
unsigned char o3 = o2 >> 3;

这意味着设置为 1 的最左边的位未保留:

01001001 => 01001 => 10000000 => 000010000
 ^           ^