【问题标题】:Calculating CRC16 on Vec<u8>在 Vec<u8> 上计算 CRC16
【发布时间】:2022-07-06 02:27:53
【问题描述】:

我通过串口发送和接收原始二进制数据,所以我有一个预定义的消息存储在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
}

但是我找不到方法来完成这项工作。上面发布的代码无法编译,因为我无法在u8u16 之间执行按位异或,但是数据被视为u8s,因为它的原始字节,所以不能改变。我可以将mut 添加到向量并使其可变然后转换为u16 但这似乎是一种冒险的方式,我不应该需要改变向量来计算校验和:

error[E0308]: mismatched types
  --> vips_interface/src\beacon_comms.rs:14:24
   |
14 |         x = crc >> 8 ^ byte;
   |                        ^^^^ expected `u16`, found `u8`

error[E0277]: no implementation for `u16 ^ &u8`
  --> vips_interface/src\beacon_comms.rs:14:22
   |
14 |         x = crc >> 8 ^ byte;
   |                      ^ no implementation for `u16 ^ &u8`

在 rust 中实现类似功能的最佳方法是什么? rust 编译器非常适合捕获整数类型溢出,但不幸的是,这是 CRC 工作原理的关键部分,因此我允许溢出的文字,但这似乎并没有解决它。我查看了一些提到 CRC 计算的 crate,但它们都没有提供我想要的东西,而且它的计算相当简单,所以我宁愿将其用作学习练习。

【问题讨论】:

    标签: rust crc crc16


    【解决方案1】:

    我没有看细节,只是编译了一下。

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

    byte 是对该切片中u8 的引用,因此*byte 是此u8 的副本(因为u8Copy),然后我们可以将其转换为@987654329 @。

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

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

    n.b. : 在你的 C++ 代码中有 (x &lt;&lt; 12)x 声明为 unsigned char;这种转变在任何情况下都会归零(Rust 对此抱怨)。 我让x 成为u16 并取消高字节,但我不确定这是你想要的。

    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
    }
    

    【讨论】:

      猜你喜欢
      • 2020-10-28
      • 1970-01-01
      • 2023-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多