我必须为固件更新创建CRC16校验和。当我发送此数据(从十六进制字符串转换为字节[])
时020000810000120000000002F001128100000C9462050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C94
我从控制器
获得CRC16-17514
现在我尝试用Java检查这个,但是我无法获得相同的值。
这是C中的原始函数:
static uint16_t crc16_update(uint16_t crc, uint8_t a)
{
crc ^= a;
for (unsigned i = 0; i < 8; ++i) {
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc = (crc >> 1);
}
return crc;
}
static uint16_t crc16(const uint8_t *b, size_t l)
{
uint16_t crc = 0;
while (l-- > 0)
crc = crc16_update(crc, *b++);
return crc;
}
这是我在java中的转换函数:
public static int crc16_update(int crc, int a) {
crc ^= a;
for (int i = 0; i < 8; ++i) {
if ((crc & 1) != 0) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = (crc << 1);
}
}
return crc;
}
public static int crc16(byte[] bytes) {
int crc = 0;
for (byte b:bytes) {
crc = crc16_update(crc, b);
}
return crc;
}
......但它不起作用。怎么了?
答案 0 :(得分:1)
public static int crc16_update(int crc, int a) {
crc ^= a;
for (int i = 0; i < 8; ++i) {
if ((crc & 1) != 0) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = (crc << 1);
作为mentioned by looper,您在C代码中有>> 1
。
}
}
return crc;
}
现在换另一个功能:
public static int crc16(byte[] bytes) {
int crc = 0;
for (byte b:bytes) {
crc = crc16_update(crc, b);
crc16_update
在Java中使用int
作为第二个参数,在C中使用uint8_t
。当字节b
设置其最高有效/符号位时,值为负数,因此当转换为int
作为crc16_update
的参数时,符号扩展,因此你得到很多你在C中没有的1位。
您需要屏蔽所有位,但最不重要的是
crc16_update(crc, ((int)b) & 0xFF);
答案 1 :(得分:0)
尝试使用>>>
运算符。
在Java中,这是无符号移位运算符,而不是保留符号的>>
。
另请注意,uint16_t
是16位类型,与Java中的short
类似。在重写位操作的算法时,尝试使用适当的位长度。
答案 2 :(得分:0)
你的问题不是java中签名的整数,而是使用了错误的数据类型。 int
有32位,您使用的算法对类型的数据大小敏感。使用short
表示16位,byte
表示8位。
如果需要,也可以使用{Anony-Mousse提到的>>>
。
答案 3 :(得分:0)
我找到了正确的方法。现在它工作了!我认为问题是短期和整数之间的实习转换。
public static int crc16_update(int crc, byte a) {
crc ^= ((a+128) & 0xff);
for (int i = 0; i < 8; ++i) {
if ((crc & 1) != 0) {
crc = ((crc >>> 1) ^ 0xA001) & 0xffff;
}
else {
crc = (crc >>> 1) & 0xffff;
}
}
return crc;
}
public static short crc16(byte[] bytes) {
int crc = 0;
for (byte b : bytes) {
crc = crc16_update(crc, b);
}
return (short) crc;
}