我的观点略有不同。 OP 正确使用位移来进入小端,因此 C++ 可移植性会很好,除非他正在处理非常规大小的字节。通信协议违背了网络上的大端约定,但有时支持遗留系统就是这样。
如果端口变量在提供的代码之外有用户,请使用 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 时,看起来您使用了一个字符,并且您的字节通过移位得到了符号扩展。这里有一些测试代码,你可以玩一下看看发生了什么。
#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]
这两个数字都必须按比例放大并进行签名,因此 0x80 变为 0xFF80。实际上,它们变成了整数,但那是另一回事了。
(0xFF80 << 8) | 0xFF80
简化为
0x8000 | 0xFF80
这就是 OR
0xFF80
AKA 65408,而不是 32896。
在这种情况下 unsigned char 是你的朋友。 Java 可能有问题,但 C++ 肯定坏了。