在 Vec <u8>上计算 CRC16



我通过串行端口发送和接收原始二进制数据,因此我有一个预定义的消息存储在u8向量中。我需要计算16位CRC并在发送之前将其附加到末尾,但是我一直遇到转换和整数溢出的问题。这就是我之前在C中完成计算的方法:

void Serial::AddCRC(void *data, int len, void *checksum)
{
uint8_t *dataPtr = (uint8_t *)data;
uint8_t *crcPtr = (uint8_t *)checksum;
uint16_t crc = 0x0;
unsigned char x;
int byteCount = 0;
while ((len--) > 0) {
x = (unsigned char)(crc >> 8 ^ dataPtr[byteCount++]);
x ^= (unsigned char)(x >> 4);
crc = (uint16_t)((crc << 8) ^ (x << 12) ^ (x << 5) ^ x);
}
crcPtr[0] = crc >> 8;
crcPtr[1] = crc &0x00ff;
}

我试图在rust中做类似的事情,但首先遇到了一些借用检查器问题,所以我试图简化它,只是写一个函数来计算crc并返回u16结果,而不需要改变向量:

#[allow(overflowing_literals)]
pub fn checksum(msg: &Vec<u8>) -> u16{
if msg.len() == 0 {return 0}
let crc: u16 = 0x0;
let x: u16;
for byte in msg.iter() {
x = crc >> 8 ^ byte;
x ^= x >> 4;
crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x;
}
crc
}

然而,我找不到一种方法来使这个工作。上面的代码发布编译失败因为我不能执行逐位xoru8u16,然而数据视为u8年代因为它的原始字节,这不能改变。我可以将mut添加到矢量并使其可变,然后转换为u16,但这似乎是一种冒险的方式,我不应该需要改变矢量来计算校验和:

error[E0308]: mismatched types
--> vips_interface/srcbeacon_comms.rs:14:24
|
14 |         x = crc >> 8 ^ byte;
|                        ^^^^ expected `u16`, found `u8`
error[E0277]: no implementation for `u16 ^ &u8`
--> vips_interface/srcbeacon_comms.rs:14:22
|
14 |         x = crc >> 8 ^ byte;
|                      ^ no implementation for `u16 ^ &u8`
在rust中实现类似函数的最佳方式是什么?rust编译器非常适合捕获整数类型溢出,但不幸的是,这是CRC工作的关键部分,因此我允许溢出的字面量,但这似乎并没有解决这个问题。我看了看一些提到CRC计算的板条箱,但没有一个提供我想要的,加上它的计算相当简单,所以我宁愿把它作为一个学习练习。

我没有看细节,只是让它编译。

首先,不需要Vec,任何切片都是合适的(即使它来自Vec)。

byte是对该切片中的u8的引用,因此*byte是该u8的副本(因为u8Copy),那么我们可以将其强制转换为u16

crc在循环中更新,因此它需要mut限定符。

x在循环中是本地的,并且在几个步骤中更新,因此它也需要mut限定符。

的被害者。:在你的c++代码有(x << 12)x声明为unsigned char。在C/c++中进行整数提升,在移位之前,x被提升为int。在Rust中,如果xu8,这个移位在任何情况下都将给出0 (Rust抱怨这一点)。我让xu16和取消上面的字节,但我不确定这是你想要什么。

pub fn checksum(msg: &[u8]) -> u16 {
let mut crc: u16 = 0x0;
for byte in msg.iter() {
let mut x = ((crc >> 8) ^ (*byte as u16)) & 255;
x ^= x >> 4;
crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x;
}
crc
}

此版本与Python中流行的实现(Klipper项目)进行了审查,并给出了与上面的版本相同的答案(上面的版本没有)

pub fn checksum(msg: &[u8]) -> u16 {
let mut crc: u16 = 0xffff;
for byte in msg.iter() {
let mut x = (*byte as u16) ^ (crc & 0xff);
x ^= (x & 0x0f) << 4;
crc = ((x << 8) | (crc >> 8)) ^ (x >> 4) ^ (x << 3);
}
crc
}

最新更新