2个字节转换为短整型

36

我正在从串口读取一个长度为 133 字节的数据包,其中最后两个字节包含 CRC 值。我使用 Java 将这两个字节值组合成一个短整型数。

以下是我的代码:

short high = (-48 & 0x00ff);
short low = 80;

short c = (short) ((high << 8) + low);

但是我没有得到正确的结果。这是因为使用了有符号的值吗? 我该如何解决这个问题?


你使用short而不是int有特别的原因吗?你的CRC值不是无符号的吗? - akarnokd
6个回答

69

记住,如果你对位移操作不太熟悉,就不必自己绞尽脑汁了。你可以使用 ByteBuffer 来帮助你:

ByteBuffer bb = ByteBuffer.allocate(2);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.put(firstByte);
bb.put(secondByte);
short shortVal = bb.getShort(0);

反过来,您可以先输入一个 short ,然后再提取字节。

顺便说一下,位运算会自动将操作数提升至至少 int 的宽度。实际上,并不存在“不允许将一个字节左移超过7位”之类的说法或其他似乎正在传播的谣言。


你是对的,它确实会转换为int,因此7位移是可以的。但是<<32是未定义的,所以它什么也不做。 - CookieOfFortune
2
回复:“你不必在位移方面纠结”; 根据我的经验(而且我在通信领域的职业生涯相当长),当处理这种类型的通信协议时,最好熟悉位操作。 - Lawrence Dol
1
Lawrence - 我基本上同意。但另一方面,在这种特定情况下,ByteBuffer类提供了一个专门设计用于完成帖子作者尝试做的事情的API... - Neil Coffey
1
一个非常合适的好锤子...当问题不那么琐碎时,你就知道它的用处了。 - Blake Neal
@LuisA.Florit - 理论上会的。但如果您只是做一次CRC检查,那么多出来的几个纳秒可能并不重要 :) 在其他情况下... 这取决于具体情况。在您需要在数据流上转换大量值的用例中,使用ByteBuffer可能更方便,JIT编译器原则上被设计为优化方法调用。(但如果性能至关重要,您需要在实践中计时...) - Neil Coffey
显示剩余3条评论

35

在Java中,当将流中的字节值转换为数字值时,必须非常小心地处理符号扩展。对于负数(来自(无符号)128-255的值),存在一个陷阱。

尝试这个方法(如果hi和lo是任何Java整数类型,则可行):

short val=(short)(((hi & 0xFF) << 8) | (lo & 0xFF));

我发现在这些情况下使用括号更加明确。


3
不需要将变量强制转换为整型,因为在进行 & 操作时会自动隐式转换为整型。 - starblue
在我的设置/测试中,这是最快的。+1。 - Luis A. Florit

14

当尝试连接字节时会发生这种情况(非常微妙)

byte b1 = (byte) 0xAD;
byte b2 = (byte) 0xCA;
short s = (short) (b1<<8 | b2);

以上代码的输出结果是0xFFCA,这是不正确的。这是因为b2是负数(byte 类型是有符号的!),这意味着当它被转换为 int 类型进行位或运算时,它将被填充为 0xF!

因此,您必须记得屏蔽填充的字节,以确保它们肯定为零:

short s = (short) (b1<<8 | b2 & 0xFF);

11
其他答案也不错,但我想强调一下类型:
short high=(-48 & 0x00ff);
short low=80;

int c= ((high & 0xFF) << 8) | (low & 0xFF);

short类型可以表示-32768到32767之间的值。53328无法很好地存储在short中,使用int代替它,因为它允许您存储无符号值,高达~109。因此,请不要将表达式转换为short,因为这会给您带来有符号值。


当处理16位CRC时,您只需要正确的位模式;最终Java值是否带符号并不重要。 - Lawrence Dol
谢谢,我在第一行使用了& 0x00FF来将无符号字节转换为短整型。例如,将0x87设置成短整型时,得到的结果是-121,而不是预期的135。 - wrapperapps

8

您可以以更易读且更优雅的方式将2个字节转换为short。

short s = ByteBuffer.wrap(new byte[]{0x01, 0x02}).getShort();
// now s equals 258 = 256 + 2

第一个字节是最高有效字节。

在我的测试中,这比手动转换或使用具有固定分配的ByteBuffer的其他答案更快。 - brimborium

0

这对我有效

short temp = ;
result[0] = (byte) ((temp >>> 8) & 0xFF);
result[1] = (byte)((temp) & 0xFF);

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