常见 CRC 算法:标准对比与选型指南
CRC 算法看着简单,选起来却挺头疼。我入行头三年,一直只用 CRC-32,觉得“反正够用”。直到有一次接手一个传感器网络项目,MCU 资源吃紧,CRC-32 算一次要几十微秒,整个循环被打乱。后来换了 CRC-8,功耗和速度都下来了。你看,选错算法真的会卡脖子。
目前业界常用的 CRC 标准有四个:CRC-8、CRC-16/CCITT、CRC-32(以太网)和 CRC-64。它们多项式不同,检错能力不同,用的地方也各不一样。下面这张核心对比表,建议你直接存下来。
| 标准 | 位数 | 多项式(十六进制) | 初始值 | 输出异或 | 典型应用 |
|---|---|---|---|---|---|
| CRC-8 | 8 | 0x07 | 0x00 | 0x00 | 1-Wire、传感器、小数据包 |
| CRC-16/CCITT | 16 | 0x1021 | 0xFFFF | 0x0000 | XMODEM、蓝牙、PPP |
| CRC-32(以太网) | 32 | 0x04C11DB7 | 0xFFFFFFFF | 0xFFFFFFFF | 以太网、ZIP、PKZip、GZIP |
| CRC-64 | 64 | 0x42F0E1EBA9EA3693 | 0x0000000000000000 | 0x0000000000000000 | ECMA-182(大文件校验) |
CRC-8:轻量级守卫
CRC-8 只有 8 位,算出来的校验值占一个字节。嗯,这里要注意:它的检错能力跟数据长度强相关。我以前在调试某款温湿度传感器时,发现它用 CRC-8 保护 8 字节数据,误检率大概 0.4%。对于逻辑控制类场景可以接受,但要是传几百字节,我建议你还是换个 16 位的。
- 优点:计算量极小,1 字节开销,适合资源受限的嵌入式设备
- 缺点:保护短数据包还好,长数据包漏检率上升
- 常见变体:CRC-8/MAXIM(0x31)用于 1-Wire 协议,很容易搞混
CRC-16/CCITT:通信老将
我个人习惯在串口、Modbus 这类场景里优先用 CRC-16/CCITT,而不是 CRC-16 的其它变种。为什么?因为 CCITT 版的多项式 0x1021 在 HD=3 时的数据包最大长度能到 65536 位,基本够用。我记得有一次调 XMODEM 传输固件,发现接收端和发送端算的 CRC 对不上。查了半天,原来是把初始值 0xFFFF 误写成了 0x0000。你想想看,0 和 0xFFFF 差的不是一星半点。
CRC-32(以太网):业界工业标准
以太网帧、ZIP 压缩、PNG 图片……这些地方用的全是 CRC-32。说白了,它已经成了“默认选项”。我建议你在大多数通用场景下无脑选它,因为它多项式选择好、分布均匀、HD=3 时能覆盖 232-1 位数据,实际几乎覆盖所有常见数据包。但代价也很实在:32 位校验码、计算比 16 位慢一倍左右,查表法需要 1KB 的查找表。
这里给你一段 Python 的实现,看看最普通的查表 CRC-32 长什么样:
def crc32_tab():
poly = 0x04C11DB7
table = []
for i in range(256):
crc = i << 24
for _ in range(8):
if crc & 0x80000000:
crc = (crc << 1) ^ poly
else:
crc <<= 1
table.append(crc & 0xFFFFFFFF)
return table
def crc32(data):
crc = 0xFFFFFFFF
tab = crc32_tab()
for byte in data:
crc = ((crc << 8) ^ tab[((crc >> 24) ^ byte) & 0xFF]) & 0xFFFFFFFF
return crc ^ 0xFFFFFFFF
binascii.crc32(),注意它已经帮你做了异或 0xFFFFFFFF。但标准 C 库的很多实现需要你手动做这一步。CRC-64:大数据时代的终极防伪
CRC-64 一般用于超大文件校验,比如文件系统、归档工具。它生成 8 字节的校验值,冲突概率极低。不过,我平时很少用它——原因很简单:大多数场景不需要。一个 2GB 的文件,CRC-32 的冲突概率也就 2-32≈1/40 亿,基本够用。只有对数据完整性要求极端严格的场合(比如金融交易快照、天文学数据)才会启用 CRC-64。
选型三问
面对这些五花八门的标准,我一般问自己三个问题:
- 数据包最大多长? 超过几 KB 就别用 CRC-8 了,至少上 16 位。
- 计算资源够吗? MCU 主频低、RAM 小 → CRC-8 或 CRC-16 查表(256 字节表);PC 端 → CRC-32 随便跑。
- 是否需要和现有协议兼容? 比如对接 Modbus 就用 CRC-16/Modbus,不要自作主张换 CCITT。
一图看懂 CRC 家族
下面这张图帮你建立整体认知。蓝色方框是“位数”层面,红色方框是“典型应用”,橙色方框是“常见变体”,绿色方框是“注意事项”。跟着箭头走,就能快速锁定你该用哪个。
说到最后,其实每个标准都有自己的舒适区。下次你在调 CRC 的时候,不妨先看看这张表,再对着流程图走一遍。我保证,你少踩 80% 的坑。嗯,今天就聊到这儿,你先拿手头的协议比对一下看看。