将int32_t编码为字节数组

时间:2014-05-01 22:34:22

标签: java c++ c

我正在尝试将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)
            );        
}    

我假设对于四个字节,我需要一个不同的操作来以正确的顺序获取字节,但我对字节操作的掌握是有限的。

3 个答案:

答案 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