【问题标题】:Unexpected result after chaining bit-shift operators in C在 C 中链接移位运算符后的意外结果
【发布时间】:2016-09-13 09:06:48
【问题描述】:

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

#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 &gt;&gt; 3 后,我应该得到 0000 1001,在 (byte &gt;&gt; 3) &lt;&lt; 7 之后,结果应该是 1000 0000,在 @987654328 之后@结果应该是0001 0000,当然是16。到底发生了什么?

【问题讨论】:

标签: c bit-shift


【解决方案1】:

运算符 >> 和

在下面一行中,变量 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
 ^           ^       

【讨论】:

  • 这个解释太棒了
  • @cuvidk 谢谢,我试试。
【解决方案2】:

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

((byte &gt;&gt; 3) &lt;&lt; 7) 被提升为int,然后在int 上执行&gt;&gt; 3

包裹到unsigned char (mod 256) 你得到((73 &gt;&gt; 3) &lt;&lt; 7) &gt;&gt; 3) % 256 = 144

使用演员表:

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

【讨论】:

  • 在一般情况下,最好将输入byte 转换为unsigned int,然后将最终结果显式转换为unsigned char。中间转换为unsigned char 仅在有意丢失最高有效位时才有意义,因为它将再次提升为int。拆分操作会更清楚。此外,右移负整数值的结果是实现定义的,因此位移操作应始终对秩为unsigned int或更高的无符号整数类型进行。固定宽度&lt;stdint.h&gt; 类型的加分。
  • 你的意思是(unsigned char)((((unsigned int)byte &gt;&gt; 3) &lt;&lt; 7) &gt;&gt; 3))?,这不是想要的输出(16),仍然是144
  • 不,这并不意味着对于数据丢失的特定情况。因此“在一般情况下”,仅作为附加信息。您的回答已经涵盖了这种具体情况。
猜你喜欢
  • 2012-04-09
  • 2022-01-11
  • 1970-01-01
  • 2012-04-03
  • 1970-01-01
  • 2015-12-11
  • 2013-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多