无符号短字节数组

时间:2015-04-30 17:10:28

标签: java c++ byte short

我必须将短信作为无符号短信发送给TCPServer。

问题是Java不支持usigned短路: 我尝试过:

byte[] data = new byte[3];
short port = 5025;

data[0] = 1;
data[1] = (byte)(port & 0xff);
data[2] = (byte)((port >> 8) & 0xff);

这就是我在C ++中将数据转换为无符号短语的方式

// Bytes to Short (uint16)
unsigned short port = (data[1] << 8) | data[2];

那么如何在Java中解决这个问题呢? (我不想改变C ++代码中的东西)

编辑:// 我的新Java代码:

byte[] data = new byte[3];
short port = 1151; // short or int doesn't matter in this case

ByteBuffer buffer = ByteBuffer.allocate(5);
buffer.put((byte) 1);
buffer.putShort(port);

out.write(buffer.array());

C ++代码:(相同)

unsigned short port = (data[1] << 8) | data[2];

如果端口在0-1151和16384-32767之间,我得到了正确的端口,但是为什么它不适用于其余端口?

2 个答案:

答案 0 :(得分:3)

没关系。只需将其放入short即可。签署short无关紧要; short仍然是16位。

重要的是这里的字节顺序。如果你通过网络发送,那就是它的大端。

ByteBuffer的默认值,以及Java的所有数字基元类型的默认值。

那么,你做什么的?对于您的特定示例,请:

// Just for a short...
final ByteBuffer buf = ByteBuffer.allocate(3);
buf.put((byte) 1);
buf.putShort(myShort);
final byte[] contents = buf.array();
// send the byte[]

现在,如果.put*()中有更多ByteBuffer,请分配必要的空间等。

但是。你说你不想改变你的C ++代码...这在架构之间是不可移植的。如果您希望在C ++中通过网络读取/写入16位值,请使用ntohs()/htons()

(也许有比这更好的API;我已经很长时间没有在C / C ++中进行过高级网络编程了)

答案 1 :(得分:0)

我的观点略有不同。 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 ++肯定会被破坏。