浅谈CRC循环冗余校验
CRC 校验(Cyclic Redundancy Check,循环冗余校验)是一种数据传输或存储中常用的差错检测技术,通过对数据进行多项式运算生成校验值,用于验证数据在传输或存储过程中是否发生错误。
一、核心原理
1. 多项式编码:将待校验的数据视为一个二进制多项式(如二进制数1011对应多项式x³ + x¹ + x⁰),并选定一个固定的生成多项式(由协议规定,如 CRC32 的生成多项式为x³² + x²⁶ + x²³ + ... + x⁰)。
CRC算法有很多种模型,但是计算方法都殊途同归。接下来以CRC-5/EPC为例,对应的多项式公式就是模2运算中的除数。对应的二进制数就是(101001)。
初始值是用于被除数减去得到真正的被除数,结果异或值就是对计算的结果再进行一次异或运算的操作数,输入输出反转就是对输入输出的二进制数是否取反。

2. 模 2 运算:用待校验数据的多项式除以生成多项式,得到的余数即为 CRC 校验值(通常附加在原始数据末尾一起传输 / 存储)。
第一步先给被除数补0,n位crc模型就补n个0。
第二步用被除数减去初始值(模2运算的减),得到真正的被除数。
第三步循环执行模2除法。
第四步得到最后的结果,补n位0余数的位数就是n位。如下图的10000.

3. 校验过程:接收方或读取方对 “原始数据 + CRC 校验值” 重新执行相同的多项式除法,若余数为 0,则认为数据未出错;否则判定数据有误。
二、主要特点
1. 检错能力强:能高效检测出数据传输中常见的错误,包括单比特错误、多比特错误、连续比特错误(突发错误)等,尤其对突发错误的检测能力突出(可检测长度不超过生成多项式阶数的突发错误)。
2. 计算效率高:算法可通过硬件电路(如移位寄存器)或软件快速实现,耗时少,适合实时性要求高的场景(如通信协议、存储设备)。
3. 实现灵活:生成多项式可根据需求选择(如 CRC8、CRC16、CRC32 等),不同多项式对应不同的检错能力和校验值长度,适配不同场景(如短数据用 CRC8,长数据用 CRC32)。
4. 非加密性:仅用于检测错误,不能防止数据被篡改(不具备加密或认证功能),其校验值可被恶意伪造。
CRC 校验因简单、高效、检错能力强,被广泛应用于通信(如以太网、串口)、存储(如硬盘、U 盘)、压缩算法等领域。
三、代码实现(CRC-8)
#include <stdint.h>
#include <string.h>
// CRC-8 多项式:0x07(x^8 + x^2 + x + 1),初始值0x00,结果不反转,无异或输出
uint8_t crc8_calculate(const uint8_t *data, uint32_t length) {
uint8_t crc = 0x00; // 初始值
const uint8_t polynomial = 0x07; // 多项式
for (uint32_t i = 0; i < length; i++) {
crc ^= data[i]; // 与当前字节异或
// 对每个比特位进行处理(8位)
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x80) { // 最高位为1时,左移后与多项式异或
crc = (crc << 1) ^ polynomial;
} else { // 最高位为0时,仅左移
crc <<= 1;
}
}
}
return crc; // 最终CRC值(无输出异或)
}
// 测试示例
#include <stdio.h>
int main() {
uint8_t test_data[] = {0x01, 0x02, 0x03, 0x04}; // 待校验数据
uint32_t data_len = sizeof(test_data) / sizeof(test_data[0]);
uint8_t crc_result = crc8_calculate(test_data, data_len);
printf("CRC-8 校验值: 0x%02X\n", crc_result); // 输出应为 0x3E
return 0;
}
四、CRC-(8\16\32)怎么选择
1. 计算效率(速度)
-
CRC8:校验值长度最短(8 位),每次处理的数据位少,多项式阶数低(通常为 8 阶),计算步骤少。无论是软件实现(循环移位异或)还是硬件实现(专用电路),速度都最快,适合对实时性要求极高的场景(如嵌入式传感器数据传输、高速串口通信)。
-
CRC16:校验值长度为 16 位,多项式阶数更高(16 阶),计算时需要处理更多比特位,循环次数是 CRC8 的 2 倍(每字节需处理 16 位)。软件实现速度略慢于 CRC8,但硬件加速下仍能满足中高速场景(如 Modbus 协议、USB 通信)。
-
CRC32:校验值长度最长(32 位),多项式阶数最高(32 阶),计算复杂度最高,循环次数是 CRC8 的 4 倍。纯软件实现时速度较慢(尤其在低性能 MCU 上),但现代 CPU 通常内置 CRC32 硬件指令(如 x86 的
CRC32指令),可大幅提升效率,适合大数据量校验(如文件校验、以太网帧校验)。
2. 检错能力
-
CRC8:检错能力最弱,能检测单比特错误、短突发错误(长度≤8 位),但对多比特错误、长突发错误(>8 位)的漏检率较高。适合数据量小、传输环境简单(干扰少)的场景(如简单传感器数据)。
-
CRC16:检错能力中等,能可靠检测单比特错误、多比特错误、突发错误(长度≤16 位),漏检率远低于 CRC8。适合中等数据量、有一定干扰的场景(如工业总线、存储设备扇区校验)。
-
CRC32:检错能力最强,能检测绝大多数多比特错误、长突发错误(长度≤32 位),漏检率极低(理论上对随机错误的漏检概率约为 1/(2³²))。适合大数据量、高可靠性要求的场景(如文件传输、磁盘镜像、网络数据包校验)。
3. 资源占用
-
内存占用:若采用查表法(预计算 CRC 值表加速),CRC8 的表大小为 256 字节(2⁸),CRC16 为 4KB(2¹⁶),CRC32 为 8KB(2³²)。在内存受限的嵌入式设备中,CRC8 更具优势,CRC32 的查表法可能受内存限制。
-
计算资源:软件实现时,CRC32 需要更多的 CPU 周期(移位、异或操作更多),在低性能 MCU(如 8 位单片机)上可能成为瓶颈;CRC8 对 CPU 资源消耗最小,适合资源紧张的场景。
简言之:长度越短,速度越快、资源占用越少,但检错能力越弱;长度越长,检错能力越强,但计算成本和资源消耗越高。实际应用需根据数据量、传输环境、硬件性能综合选择。
更多推荐

所有评论(0)