我有一个从套接字(小端)读入的字节流。 有人能告诉我为什么只有下面的方法中的最后一个给出正确的答案? 我怀疑它与进位位有关,但不确定。我总是发现这个时候 以十六进制形式打印二进制数据
e.g。
printf("%02X", data);
它有时会在前面用0xff打印出有趣的值。修复它的方法似乎 这样做。当数据也是char数据类型时,偶尔会发生这种情况:
printf("%02X", data & 0xff);
这是我用字节流看到的简化示例。 字节是我从套接字读取的字节流。
int main(int argc, char* argv[])
{
union {
unsigned int num;
char bytes[4];
} x;
x.num = 500;
printf("x.num=%u\n", x.num);
unsigned int method1 = x.bytes[0] | (x.bytes[1] << 8) | (x.bytes[2] << 16) | (x.bytes[3] << 24);
printf("method1 = %u\n", method1);
unsigned int method2 = x.bytes[0] + (x.bytes[1] << 8) + (x.bytes[2] << 16) + (x.bytes[3] << 24);
printf("method2 = %u\n", method2);
unsigned int method3 = (x.bytes[0] & 0xff | (x.bytes[1] & 0xff) << 8
| (x.bytes[2] & 0xff) << 16 | (x.bytes[3] & 0xff) << 24);
printf("method3 = %u\n", method3);
return 0;
}
哪个输出:
x.num=500
method1 = 4294967284
method2 = 244
method3 = 500
只有最后一次提取实际上是正确的。
我的方法是建立最优的数字吗?我还尝试了memcpy
变量,但又不可靠。
答案 0 :(得分:4)
当将有符号数据类型转换为更高数据类型时,最高有效位用作符号位。你的工会应该有unsigned char
。在你的情况下500 = 256 + 244 = 0x1f4并且字节244具有最高有效位设置,所以当提升变为0xfffffff4时。
答案 1 :(得分:1)
为什么不在unsigned char bytes[4]
中使用union
?如果没有签名规范,您不知道您的char
是签名还是未签名(取决于平台和编译器),因此对它们进行算术会产生特殊结果并不奇怪。
如果您的编译器确实决定将您的“神秘字符数据”视为已签名而非无符号,则您可能观察到的0xFF
可能是由于符号扩展所致。
根据经验,当char
用于表示“用于进一步处理或显示目的的字节”时,我建议始终使用unsigned char
来确定 - 我不记得何时上一次是我真的想要一个签名的字符! - )
答案 2 :(得分:0)
在小端架构中,数字500
(256 + 244
)将存储为:
+-----------+-----------+-----------+-----------+
| 244(0xf4) | 1(0x01) | 0(0x00) | 0(0x00) |
+-----------+-----------+-----------+-----------+
并且,因为您自己使用char
,所以C标准没有指定它是有符号还是无符号(它是实现定义的)。在您的情况下,它似乎已签名。
除此之外:当您将“瘦”数据值加载到更宽的数据值时,符号扩展以二进制补码编码发生。在细数的最高位为1(表示负数)的情况下,这扩展到更宽类型中的所有更高位。这样做的原因是为了保持数字的性质。例如,8位中的-12为
0xf4
,16位为0xfff4
,而256位为0xfffffffffffffffffffffffffffffff4
。
这意味着244
(-12
或0xf4
)将被转换为0xfffffff4
。这可能会严重破坏您的|
和+
解决方案。
您将获得的价值是:
x0 0xfffffff4
x1<<8 0x00000100
x2<<16 0x00000000
x3<<24 0x00000000
方法1使用|
,因此最终得到0xfffffff4
(x1中的另一位已经在x0中设置,因此它不受影响,x2 / x3全部为零),这是{{ 1}}作为4294967284
。
方法2添加它们,以便最终得到unsigned int
当然包装,丢弃高字节并留下0x1000000f4
或244。
在方法3中,符号扩展名仍会发生,但之前 0xf4
&
。这是0xff
操作,可以反转符号扩展的效果,并将&
转回0xfffffff4
。
正如其他人已经提到的那样,明确使用0xf4
。这可以防止在升级到更大的整数类型时发生符号扩展。