我有一个从套接字读取的字节流(小端)。谁能告诉我为什么下面的最后一种方法给出了正确的答案?我怀疑这与进位有关,但不确定。在打印十六进制格式的二进制数据时,我总是发现这一点。
例如:
printf("%02X", data);它有时会打印出前面带有0xff的可笑的值。修复它的方法似乎是这样做。当数据也是char数据类型时,仍然会偶尔发生这种情况:
printf("%02X", data & 0xff);下面是我在字节流中看到的一个简化示例。其中bytes是我从套接字读取的字节流。
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,但这同样不可靠。
发布于 2010-08-09 09:07:36
当有符号数据类型被转换为更高的数据类型时,最高有效位被用作符号位。你的工会里应该有unsigned char。在你的例子中,500 = 256 + 244 = 0x1f4,字节244设置了最高有效位,所以当提升时变成0xfffffff4。
发布于 2010-08-09 09:06:53
为什么不在union中使用unsigned char bytes[4]呢?如果没有符号规范,你就不知道你的char是有符号的还是无符号的(取决于平台和编译器),所以它们的算术运算会产生特殊的结果也就不足为奇了。
如果您的编译器确实决定将您的“神秘字符数据”视为有符号而不是无符号,那么您可能已经观察到0xFF可能是由于符号扩展造成的。
根据经验,当char被用来表示“用于进一步处理或显示的一个字节”时,我建议始终使用unsigned char来确定--我不记得上一次我真正想要有符号字符是什么时候!)
发布于 2010-08-09 09:14:48
在小端体系结构中,数字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都是零),它是4294967284作为unsigned int。
方法2添加了它们,所以您最终得到了0x1000000f4,它当然会包装,去掉高位字节,只剩下0xf4或244。
在方法3中,符号扩展仍然发生,但在您使用0xff &它之前。正是&操作逆转了签名扩展效果,并将您的0xfffffff4重新转换为0xf4。
正如其他人已经提到的,显式地使用unsigned char。这将防止在升级到更大的整数类型时发生符号扩展。
https://stackoverflow.com/questions/3436749
复制相似问题