C++ C/C中的数字重组++
我有一个字节流,它是从一个套接字小端点读入的。 有人能告诉我为什么只有下面最后一种方法给出正确答案吗? 我怀疑这与携带钻头有关,但不确定。我总是发现当 以十六进制形式打印二进制数据 e、 g 它有时会打印出前面有0xff的有趣值。解决这个问题的方法似乎很简单 我要这样做。当数据也是char数据类型时,这种情况仍然偶尔发生:C++ C/C中的数字重组++,c++,C++,我有一个字节流,它是从一个套接字小端点读入的。 有人能告诉我为什么只有下面最后一种方法给出正确答案吗? 我怀疑这与携带钻头有关,但不确定。我总是发现当 以十六进制形式打印二进制数据 e、 g 它有时会打印出前面有0xff的有趣值。解决这个问题的方法似乎很简单 我要这样做。当数据也是char数据类型时,这种情况仍然偶尔发生: printf("%02X", data & 0xff); 下面是一个简化的例子,来自我看到的字节流。 其中bytes是我从套接字读取的字节流 int main(in
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;
}
只有最后的摘录才是正确的。
我建立数字的方法是最理想的吗?我还尝试对变量使用memcpy,但同样不可靠。为什么不在联合中使用无符号字符字节[4]?如果没有签名规范,您就不知道字符是有符号的还是无符号的,这取决于平台和编译器,因此基于它们的算术给出特殊的结果也就不足为奇了
如果编译器确实决定将神秘字符数据视为有符号数据而不是无符号数据,那么您可能观察到的0xFF可能是由于符号扩展造成的
根据经验,当char用于表示一个字节以供进一步处理或显示时,我建议始终使用unsigned char作为定义-我不记得上一次是什么时候,我真的想要一个signed char- 当有符号数据类型转换为更高的数据类型时,最高有效位用作符号位。您的联合体中应该有未签名字符。在您的情况下,500=256+244=0x1f4,字节244具有最高有效位集,因此当升级为0xFFFFF4时。在小端结构中,数字500 256+244将存储为:
+-----------+-----------+-----------+-----------+
| 244(0xf4) | 1(0x01) | 0(0x00) | 0(0x00) |
+-----------+-----------+-----------+-----------+
而且,因为您自己使用char,所以C标准没有指定它是有符号的还是无符号的,而是由它的实现定义的。在您的情况下,它似乎已签名
旁白:当您将一个较薄的数据值加载到一个较宽的数据值中时,符号扩展发生在2的补码编码中。如果细数的顶部位为1,表示负数,则扩展到更宽类型中的所有高位。这样做的原因是为了保留数字的性质。例如,8位中的-12是0xf4,16位中的是0xfff4,256位中的是0xFFFFFFFFFFFFFFFFF4
这意味着244-12或0xf4将符号扩展为0xFFFFF4。这可能会严重破坏你的|和+解决方案
您将获得以下值:
x0 0xfffffff4
x1<<8 0x00000100
x2<<16 0x00000000
x3<<24 0x00000000
方法1使用|因此最终得到0xFFFFF4,x1中的另一位已在x0中设置,因此它不受影响,x2/x3均为零,即4294967284作为无符号整数
方法2添加了它们,因此最终得到0x1000000f4,这当然会进行包装,丢弃高字节,留下0xf4或244
在方法3中,符号扩展仍然发生,但在您使用0xff进行扩展之前。正是该&操作反转了符号扩展的效果,并将0xfffff4转换回0xf4
正如其他人已经提到的,显式使用unsigned char。这将防止升级为更大的整数类型时发生符号扩展。感谢您的详细解释。
+-----------+-----------+-----------+-----------+
| 244(0xf4) | 1(0x01) | 0(0x00) | 0(0x00) |
+-----------+-----------+-----------+-----------+
x0 0xfffffff4
x1<<8 0x00000100
x2<<16 0x00000000
x3<<24 0x00000000