c - 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 开始。这个对吗?他们为什么以这种方式使用运算符?
解决方案
它正在7-b
从src[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
循环。
推荐阅读
- arrays - SwiftUI 从列表中删除行
- c - Multiple extra-cflags of a makefile
- javascript - 同一页面上具有随机图形的多个 html 画布元素
- lua - table.move 到底是做什么的,我什么时候使用它?
- python - Python - Pandas Groupby - 何时使用 apply() / agg()
- javascript - 如何创建保存变量的变量
- javascript - 邮递员测试以检查响应正文的每个项目是否在数组中都存在 id
- javascript - 如何遍历axios拦截器并检查是否已经添加了拦截器
- neo4j - Neo4j中的双向递归
- c++ - ObjC 应用程序项目在引用导入到应用程序的 ObjC 类库中的 .cpp 文件中的 C 函数时出现构建错误