首页 > 解决方案 > C Zephyr SDK CRC16 实现

问题描述

我在 zephyr 实现中环顾四周,发现了这种计算 crc16 校验和的方法:

u16_t crc16(const u8_t *src, size_t len, u16_t polynomial,
        u16_t initial_value, bool pad)
{
    u16_t crc = initial_value;
    size_t padding = pad ? sizeof(crc) : 0;
    size_t i, b;

    /* src length + padding (if required) */
    for (i = 0; i < len + padding; i++) {

        for (b = 0; b < 8; b++) {
            u16_t divide = crc & 0x8000UL;

            crc = (crc << 1U);

            /* choose input bytes or implicit trailing zeros */
            if (i < len) {
                crc |= !!(src[i] & (0x80U >> b));
            }

            if (divide != 0U) {
                crc = crc ^ polynomial;
            }
        }
    }

    return crc;
}

我在这里绊倒了这条线:

                crc |= !!(src[i] & (0x80U >> b));

我不明白他们为什么在这一行中使用布尔运算符 (!!)。据我了解,这就是它的作用:它基本上做了一个隐式的“强制转换”,它认为它在右边的操作数是一个布尔值并否定它两次​​,除了使输出为 0 或 1 之外,它没有做任何事情,具体取决于如果表达式(src[i] & (0x80U >> b))大于 0 开始。这个对吗?他们为什么以这种方式使用运算符?

标签: ccrc

解决方案


它正在7-bsrc[i]的低位插入位crc。如果该位是 a 1,它将在 的结果中的某个位置,&则将!!其转换为1低位中的 a ,然后将其或运算为crc

这真是让人看着就心疼。一种更好更干净的方法是crc |= (src[i] >> b) & 1;倒计时b而不是倒计时。例如int b = 8; do { b--; ... } while (b);。更好的是只排他或循环后的字节,它做同样的事情:

/* src length + padding (if required) */
for (i = 0; i < len + padding; i++) {
    for (b = 0; b < 8; b++)
        crc = crc & 0x8000 ? (crc << 1) ^ polynomial : crc << 1;
    if (i < len)
        crc ^= src[i];
}

优化编译器将展开b循环。


推荐阅读