在 C 中链接移位运算符后的意外结果
Posted
技术标签:
【中文标题】在 C 中链接移位运算符后的意外结果【英文标题】:Unexpected result after chaining bit-shift operators in 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 >> 3
后,我应该得到 0000 1001,在 (byte >> 3) << 7
之后,结果应该是 1000 0000,在 @987654328 之后@结果应该是0001 0000,当然是16。到底发生了什么?
【问题讨论】:
Integer promotion,每隔一段时间就会有人问这样的问题。 可能,但我不知道这与整数提升有关。 要记住一条重要的规则:int
是 C 中的一种特殊类型,所有较小的类型在计算过程中都会被提升为 int
。这也是为什么为 16 位架构编译的源代码(其中int
是 16 位宽)在编译为 32 位时会有不同的行为。
Why does combining two shifts of a uint8_t produce a different result?的可能重复
Unexepected behavior from multiple bitwise shifts on the same line
【参考方案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 >> 3) << 7)
被提升为int
,然后在int
上执行>> 3
包裹到unsigned char
(mod 256) 你得到((73 >> 3) << 7) >> 3) % 256
= 144
使用演员表:
unsigned char chain = ((unsigned char)((byte >> 3) << 7) >> 3);
【讨论】:
在一般情况下,最好将输入byte
转换为unsigned int
,然后将最终结果显式转换为unsigned char
。中间转换为unsigned char
仅在有意丢失最高有效位时才有意义,因为它将再次提升为int
。拆分操作会更清楚。此外,右移负整数值的结果是实现定义的,因此位移操作应始终对秩为unsigned int
或更高的无符号整数类型进行。固定宽度<stdint.h>
类型的加分。
你的意思是(unsigned char)((((unsigned int)byte >> 3) << 7) >> 3))
?,这不是想要的输出(16),仍然是144
不,这并不意味着对于数据丢失是的特定情况。因此“在一般情况下”,仅作为附加信息。您的回答已经涵盖了这种具体情况。以上是关于在 C 中链接移位运算符后的意外结果的主要内容,如果未能解决你的问题,请参考以下文章