CRC校验用数组实现的核心是预计算256项查表;对每个字节i(0–255),初始化temp=i,左移8位后与0x1021多项式迭代异或,得到crc_table[i]。

用数组实现 CRC 校验,核心是预计算一张 256 项的查表(lookup table),把每个可能的字节(0–255)与当前 CRC 寄存器组合后产生的新 CRC 值提前算好。这样每次处理一个字节时,只需一次查表 + 一次异或,无需逐位运算,效率高、代码简洁,特别适合单片机等资源受限环境。
准备 CRC-16 查表数组
以常用 CRC-16/CCITT(生成多项式 G(x) = x¹⁶ + x¹² + x⁵ + 1,即 0x1021)为例,需构造一个 uint16_t crc_table[256]:
- 对每个字节 i(0 到 255),初始化 temp = i
- 循环 8 次:若 temp 最高位为 1,则 temp = (temp
- 取低 16 位存入 crc_table[i]。
该表只需在程序启动时计算一次(或直接定义为 const 数组),后续校验全程复用。
用数组查表计算字节流 CRC 值
假设待校验数据为 uint8_t data[],长度为 len,初始 CRC 值通常设为 0xFFFF(CRC-CCITT 规范):
- 设置 crc = 0xFFFF;
- 对每个 data[i]:crc = (crc > 8 ^ data[i]];
- 注意:此处使用的是“高位先行”+“寄存器初值 0xFFFF”的标准组合;
- 若协议要求结果取反(如 PPP 协议),最后再执行 crc = ~crc。
整个过程不涉及位操作循环,每字节仅 2 次移位、1 次查表、2 次异或,执行稳定且可预测。
处理单个字节变量的 CRC 计算
当只校验一个字节(例如传感器返回的状态码),仍需按完整流程走:
- 不能直接查表得结果——因为 CRC 是累积状态,依赖前序寄存器值;
- 正确做法:以初始值(如 0xFFFF)开始,将该字节作为唯一输入调用上述查表函数;
- 例如:crc = update_crc(0xFFFF, byte_val),其中 update_crc 就是上面的单步查表逻辑;
- 若用于应答帧校验,该单字节 CRC 值常需拆成高低字节(crc & 0xFF 和 crc >> 8)追加到报文末尾。
验证时同样使用同一张表
接收端校验时,把**含 CRC 校验码在内的整帧数据**(包括原本附加的 2 字节 CRC)一起送入相同算法:
- 起始 crc = 0xFFFF;
- 逐字节处理全部数据(含最后两个 CRC 字节);
- 若最终 crc == 0x0000(或协议规定的 Magic Value,如 0xF0B8),说明无错;
- 这利用了 CRC 的数学特性:原始数据 + 其 CRC 组合成的帧,再次计算 CRC 应得固定余数。

















