数据的守护神:CRC 校验算法的极致优化
CRC (循环冗余校验) 是嵌入式系统中数据完整性的最后一道防线。无论是固件升级 (OTA) 时的文件校验,还是 Modbus 通信的数据包检查,都离不开它。
1. 原理简述
CRC 的数学本质是模二除法。
把数据看作一个巨大的二进制多项式 $D(x)$,用一个生成多项式 $G(x)$ 去除它,得到的余数 $R(x)$ 就是 CRC 校验码。
模二运算中,加减法等同于**异或 (XOR)**,没有进位借位,这使得它非常适合硬件实现。
2. 软实现之道:时间 vs 空间
在没有硬件 CRC 外设的单片机上,我们通常有两种软件实现方式。
2.1 按位移位法 (Bit-by-Bit) —— 省 Flash,费 CPU
这是最符合数学定义的方法。对每个字节的每一位进行计算。
1 | uint8_t CRC8_Slow(uint8_t *data, size_t len) { |
- 优点:代码极短,Flash 占用极小。
- 缺点:每个字节要循环 8 次,处理 1KB 数据需要 8KB 次循环,慢如蜗牛。
2.2 查表法 (Table-Driven) —— 费 Flash,省 CPU
我们可以预先计算出所有可能的字节 (0x00 ~ 0xFF) 经过 CRC 计算后的结果,存入一个 256 字节的数组(对于 CRC16/32 则是更大)。
1 | // 预先算好的表 |
- 优点:速度飞快,比移位法快 8 倍以上。
- 缺点:CRC8 需 256 字节 ROM,CRC32 需 1KB ROM。
3. C++ 黑魔法:编译期生成表
手算或复制粘贴 256 个数到代码里是很蠢的。万一换了个多项式,整个表都要重算。
在 C++17 中,我们可以利用 constexpr 让编译器在编译阶段帮我们算出这个表!
1 | template <uint8_t Poly> |
生成的汇编代码中,crc_table 就是一段已经算好的常量数据。
总结
- 资源极度受限(Flash < 4KB):用移位法。
- 追求速度(大部分场景):用查表法。
- 追求优雅:用 C++
constexpr生成查表。
- Title: 数据的守护神:CRC 校验算法的极致优化
- Author: Evek Golden
- Created at : 2024-04-05 22:33:00
- Updated at : 2026-06-12 08:57:02
- Link: https://blog.cocodemo.uno/posts/crc7j2w/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments