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

cuv*_*cuv 2 c bit-shift

我无法弄清楚为什么链接位移操作不会返回与不链接它们相同的结果.

#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;
}
Run Code Online (Sandbox Code Playgroud)

我期待这两个printf调用打印出来16因为二进制中的73是0100 1001.申请后byte >> 3我应该得到0000 1001,(byte >> 3) << 7结果应该是1000 0000,(((byte >> 3) << 7) >> 3)结果应该是0001 0000,当然是16.什么是实际发生了什么?

250*_*501 5

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

在以下行中,变量字节被提升为int类型,然后对此类型执行所有三个操作:

unsigned char chain = (((byte >> 3) << 7) >> 3);
Run Code Online (Sandbox Code Playgroud)

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

01001001 => 01001 => 010010000000 => 010010000 
 ^           ^        ^               ^
Run Code Online (Sandbox Code Playgroud)

在下面的代码中,变量被提升为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;
Run Code Online (Sandbox Code Playgroud)

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

01001001 => 01001 => 10000000 => 000010000
 ^           ^       
Run Code Online (Sandbox Code Playgroud)