C Zephyr SDK CRC16 Implementation



我在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 开始。 这是对的吗?他们为什么要以这种方式使用运算符?

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

这看起来真的很痛苦。一个更好,更干净的方法是crc |= (src[i] >> b) & 1;b倒计时而不是向上倒计时。F.D.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循环。

最新更新