我在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
. 如果该位是一个 1
的结果中的某处。&
జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ !!
变成 1
的低位,然后再将其转化为 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
循环。