我正在计算我的数据的16位校验和,我需要将其发送到服务器,它必须重新计算并与提供的校验和匹配。我得到的校验和值是int,但是我只有2个字节用于发送值。所以我在调用int
方法时将short
强制转换为shortToBytes
。这工作正常,直到校验和值小于32767,此后我得到负值。
事情是java没有无符号的原语,所以我无法发送大于允许的签名short
的最大值的值。
我该怎么做,将int转换为short并通过网络发送而不用担心截断和签名& unsigned int。
另外,我也有java程序在运行。
private byte[] shortToBytes(short sh) {
byte[] baValue = new byte[2];
ByteBuffer buf = ByteBuffer.wrap(baValue);
return buf.putShort(sh).array();
}
private short bytesToShort(byte[] buf, int offset) {
byte[] baValue = new byte[2];
System.arraycopy(buf, offset, baValue, 0, 2);
return ByteBuffer.wrap(baValue).getShort();
}
答案 0 :(得分:1)
首先,Java int
,short
和byte
类型都是未签名的签名。其次,当您将Java int
转换为short
等时,您将获得静默截断。
这是否重要取决于校验和算法的性质。如果它是一个简单的求和或按位算法,那么当使用Java有符号整数实现时,该算法很可能很好。例如,那些“负”16位校验和在被期望无符号值的东西解释时可能是正确的。
另一方面,乘法和除法的语义是必须单独处理有符号和无符号的风格。 (至少,这是我从查看x86指令集的不科学方法推断出来的......它有单独的有符号与无符号乘法和除法的指令。)
编辑我知道您正在计算CRC-16。由于可以通过移位和异或来计算,因此在计算过程中不应该考虑有符号和无符号数。
简而言之,您无需担心。
答案 1 :(得分:1)
char
是无符号16位类型。实际上它是Java中唯一的无符号类型。您可以使用它来计算校验和,然后使用ByteBuffer
来获取字节,或者只使用按位和右移来获取字节。
请记住byte
已签名。
答案 2 :(得分:1)
您仍然获得与服务器相同的位值。因此,要查看正确的数值,请将ByteBuffer.wrap(baValue).getShort()
替换为ByteBuffer.wrap(baValue).getInt()
。这应该给你与服务器相同的数值。
答案 3 :(得分:0)
当你说你得到负值时,我认为你的意思是当你读取16位值并将其转换为整数时。原因是当short
扩展为int
时,符号扩展会导致最高位(即1)被复制。简单的解决方法是按位和重建的0xFFFF
整数,这将确保只有最不重要的16位非零。