我有一个稍微不同的观点。OP 正确使用位移来进入小端模式,所以 C++ 的可移植性会很好,除非他正在处理非常规大小的字节。通信协议违反了大端网络约定,但有时支持旧系统就是这样。
如果 port 变量在提供的代码之外有用户,请使用 int 并仅发送您在上面的 Java 示例中想要的位。如果您正在传递该端口,则不断调整该死的符号位非常麻烦,迟早会出错。如果没有其他人需要使用端口,则符号将无关紧要。
byte[] data = new byte[3];
int port = 5025; // short or int doesn't matter in this case
data[0] = 1;
data[1] = (byte)(port & 0xff);
data[2] = (byte)((port >> 8) & 0xff);
当读取并得到65440时,看起来你使用了char类型,而且通过移位操作进行了符号扩展。以下是一些测试代码,可以让你尝试并了解发生了什么。
#include <cstdio>
int main()
{
unsigned short val = 32896;
char hi = (char)((val >> 8) & 0xFF);
char lo = (char)(val &0xFF);
printf("Watch what the sign bit can do to the bytes here:\n");
printf("Value: %d, raw in hex: %04x, Hi byte: %02x, Low byte: %02x\n", val, val, hi, lo);
printf("This one only works if the low byte doesn't sign extend\n");
char datas[3] = {0, hi, lo};
unsigned short port = (datas[1] << 8) | datas[2];
printf("Reassembled short: %u, In Hex: %04x\n", port, port);
printf("This one works, but will not for an integer\n");
port = (datas[1] << 8) | (datas[2] & 0xFF);
printf("Reassembled short: %u, in Hex: %04x\n", port, port);
unsigned int bigport = (datas[1] << 8) | (datas[2] & 0xFF);
printf("Reassembled int: %u, in Hex: %04x\n", bigport, bigport);
printf("With unsigned characters it just works\n");
unsigned char datau[3] = {0, hi, lo};
port = (datau[1] << 8) | datau[2];
printf("Reassembled short: %u, In Hex: %04x\n", port, port);
bigport = (datau[1] << 8) | (datau[2] & 0xFF);
printf("Reassembled int: %u, in Hex: %04x\n", bigport, bigport);
}
输出:
Watch what the sign bit can do to the bytes here:
Value: 32896, raw in hex: 8080, Hi byte: ffffff80, Low byte: ffffff80
This one only works if the low byte doesn't sign extend
Reassembled short: 65408, In Hex: ff80
This one works, but will not for an integer
Reassembled short: 32896, in Hex: 8080
Reassembled int: 4294934656, in Hex: ffff8080
This one just works
Reassembled short: 32896, In Hex: 8080
Reassembled int: 32896, in Hex: 8080
所以发生了什么?
(datas[1] << 8) | datas[2]
两个数字必须缩放到short并且是有符号的,因此0x80变成了0xFF80。实际上它们变成了整数,但这是另一个故事。
(0xFF80 << 8) | 0xFF80
简化为
0x8000 | 0xFF80
并且 进行逻辑或运算,得到
0xFF80
AKA 65408,而不是32896。
在这种情况下,无符号字符是您的好朋友。Java可能存在问题,但C++肯定有问题。
data[1] << 8
是04<<8
,变成0400。data[2]
是80(-128),但它即将与16位数字组合,因此它变成FF80(在有符号16位中为-128)。0400|FF80
=FF80(在无符号16位中为65408)。你必须修复C++代码。它已经损坏了。 - user4581301