我正在尝试将int32_t编码为C ++中的字节数组,然后通过网络套接字将其传递给java并将其解码回一个始终为32位的java整数。
使用此代码,我已成功使用16位整数,无符号和带符号的16位整数:
c ++ side
void Codex::encodeShortToArray(uint16_t inputShort, unsigned char buffer[],int pos)
{
// insure its in network byte order
inputShort = htons(inputShort);
// encode the bytes
buffer[pos+1] = (inputShort >> 8);
buffer[pos+0] = inputShort;
}
java方面:
public static short decodeShortFromArray(byte[] array, int pos)
{
return (short)
(
(array[pos+0] << 8)
+ (array[pos+1] & 0xff)
);
}
但是当我尝试使用32位整数时,它只适用于较小的无符号数。传输后,大数字或带符号的数字会返回不同的值。
c ++ side
void Codex::encodeIntToArray(uint32_t inputInt, unsigned char buffer[],int pos)
{
// insure its in network byte order
inputInt = htonl(inputInt);
// encode the bytes
buffer[pos+3] = (inputInt >> 24);
buffer[pos+2] = (inputInt >> 16);
buffer[pos+1] = (inputInt >> 8);
buffer[pos+0] = inputInt;
}
java方面:
public static int decodeIntFromArray(byte[] array, int pos)
{
return (int)
(
(array[pos+0] << 24)
+ (array[pos+1] << 16)
+ (array[pos+2] << 8)
+ (array[pos+3] & 0xff)
);
}
我假设对于四个字节,我需要一个不同的操作来以正确的顺序获取字节,但我对字节操作的掌握是有限的。
答案 0 :(得分:2)
我认为你遇到的问题是字节是用Java签名的,而<<
运算符是为了提升整数的参数。当你做类似的事情时:
array[pos] << 24
实际发生的事情更好地表达为:
(int)array[pos] << 24
如果array[pos]
(无符号)大于127(即设置了最高位),那么Java会将其视为负数,然后你有额外的符号位被移位。
解决方案是屏蔽这些额外的位:
(array[pos] & 0xFF) << 24
// ^~~~~~
一个简单的例子:0x8000(无符号)是十进制32768.所以你希望0x80 << 8
给你32768.尝试运行以下Java代码:
System.out.println(((byte)0x80) << 8);
System.out.println(((byte)0x80 & 0xFF) << 8);
当你屏蔽额外的符号位(第二个)时,你会得到预期的答案。
所以你的解码方法应该是:
public static int decodeIntFromArray(byte[] array, int pos)
{
return (int)
(
((array[pos+0] & 0xFF) << 24)
+ ((array[pos+1] & 0xFF) << 16)
+ ((array[pos+2] & 0xFF) << 8)
+ ((array[pos+3] & 0xFF)
);
}
答案 1 :(得分:0)
您无需使用“网络”订单通过网络发送。你可以做到
void Codex::encodeIntToArray(uint32_t inputInt, unsigned char buffer[],int pos) {
*(uint32_t *)(buffer + pos) = inputInt;
}
public static int decodeIntFromArray(byte[] array, int pos) {
new ByteBuffer(array).order(ByteOrder.LITTLE_ENDIAN).getInt(pos);
}
答案 2 :(得分:0)
它看起来像是htonl线。你为什么这样做?即使它是你的意思,你也没有调用java版本将它恢复到你的机器端序。如果你在小端机器上,它将使订单大端。你不好的做法是在一个名为encode int to array的函数上有一个endian转换器。您应该使用IO流进行转换,但除非您需要创建大小端的客户端,否则IDK会为您打扰。您没有将网络订单转换回java端的机器订单。
无论如何IDK Java很好但是签名值可能有问题。假设0x80&lt;&lt; 24是int_min(−2,147,483,648
)然后你的代码应该在删除c ++中的htonl行后工作。你也不需要&amp; java中的0xFF。尝试使用int 0x12345678,看看你在Java端获得了什么。现在我怀疑你得到0x78563412,这是2018915346