Java:将整数拆分为2个字节,然后再将它们组合成一个整数

12

我目前正在开展一个项目,通过串口从Java应用程序向Arduino发送数据。

我的问题是:我需要将一个整数分成两个字节,然后在Arduino中将它们组合成一个整数。但相反地(Arduino->Java),只会给我带来麻烦。 Arduino部分并不那么困难,而且运行得很好,但尽管我已经查看了这里发布的相关问答,我仍然无法弄清楚如何将这些字节正确地组合成一个int。

这是Java代码,它就是不起作用:

int in = 500;
byte[] data = new byte[2];

data[0] = (byte)(in & 0xFF);
data[1] = (byte)((in >> 8) & 0xFF);

int res = data[0] | (data[1] << 8);

我从控制台得到的输出是:

data[0] = -12  
data[1] = 1  
res = -12

但我需要res为500!


2
一个整数由4个字节组成... - Obicere
如果我理解正确的话,您想将5存储在data [0]中,将0存储在data [0]中。那另一个0呢?它不应该是byte[3]吗? - Vikas V
问题在于你将其转换为使用byte[]。如果你使用short[]int[],它会按预期工作。 - c.s.
4个回答

17

Java使用有符号字节(C、C++、C#使用无符号字节),因此您应该注意补码表示法(对于负值):

int in = 500; 
byte[] data = new byte[2]; // <- assuming "in" value in 0..65535 range and we can use 2 bytes only

data[0] = (byte)(in & 0xFF);
data[1] = (byte)((in >> 8) & 0xFF);

int high = data[1] >= 0 ? data[1] : 256 + data[1];
int low = data[0] >= 0 ? data[0] : 256 + data[0];

int res = low | (high << 8);

1
谢谢,这是我找到的最佳答案。如果可以的话,我会给+2。 - justinkoh
宝贵的代码。救了我的一天! - Denis V

5
问题出现在这里:
int res = data[0] | (data[1] << 8);
| 运算符需要 int 类型的运算数,而 data[0] 是从 byte 类型提升到了 int 类型。由于 byteint 都是有符号类型,该提升将字节值 -12 转换为整数 -12,并通过符号扩展实现。
最简单的修复方法如下:
int res = (data[0] & 0xff) | ((data[1] & 0xff) << 8);

这里还有另一个问题。通常来说,你无法用2个字节表示一个intint类型是32位宽的,需要4个字节...来表示整个范围。


关于您的编辑:是的,我知道,但我不需要整个Integer范围,因为Arduino上的Integers是2个字节。我没有计划发送比2个字节表示的更大的任何内容。 - user2655904
你应该考虑使用Java的short - Stephen C
是的,我也是这么想的,但我想看看它是否也适用于整数。 - user2655904
对于“short”和“int”,您将遇到相同的问题(关于符号扩展)。唯一的区别是您需要将表达式转换为“short”。Java的按位“&”、“|”和“^”运算符仅定义为“int,int->int”或“long,long->long”。 - Stephen C

3

另一种可能性就是使用NIO

ByteBuffer buf = ByteBuffer.allocate(2);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putShort(500);
byte[] result = buf.array(); // [-12, 1]

buf = ByteOrder.wrap(result);
buf.order(ByteOrder.LITTLE_ENDIAN);
short res = buf.getShort(); // 500

这样有以下优点:

  • 与Java IO集成 - 您不需要获取数组 - 可以直接将其传递给通道。
  • 显式规定排序
  • 自Java 1.4以来,它就在标准库中了

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接