文章目录
CRC(Cyclic Redundancy Check,循环冗余校验)是一种根据数据产生简短固定位数校验码的算法,主要用于检测数字数据在传输或存储过程中是否发生错误。它的检错能力强、实现简单,在通信、存储等领域应用非常广泛。
核心原理:多项式除法
CRC校验的核心思想是:将二进制数据看作一个多项式的系数,然后使用一个预设的"除数"多项式(即生成多项式)去除这个数据多项式,得到的余数就是CRC校验码。
具体步骤
1、数据多项式:假设要发送的数据是 1011001(二进制)。可以把它表示为一个多项式:
bash
M(x) = 1*x^6 + 0*x^5 + 1*x^4 + 1*x^3 + 0*x^2 + 0*x^1 + 1*x^0 = x^6 + x^4 + x^3 + 1
2、生成多项式:发送方和接收方必须事先约定一个生成多项式 G(x)。它的最高次幂记为 r(r位)。常见标准如:
bash
CRC-8:x^8 + x^2 + x + 1 (对应二进制:1 0000 0111)
CRC-16-CCITT:x^16 + x^12 + x^5 + 1 (对应二进制:1 0001 0000 0010 0001)
CRC-32(以太网、ZIP等):x^32 + x^26 + x^23 + ... + x^2 + x + 1
3、补零并做模2除法:
在原数据比特串后面补 r 个0,得到 M(x) * x^r。这样做的目的是为余数(校验码)留出位置。
用这个补零后的数,除以生成多项式 G(x),除法使用 模2除法(即按位异或,不借位、不进位)。
4、得到CRC校验码:模2除法得到的余数(长度一定小于r位,如果不足r位则前面补0)就是CRC校验码。
5、发送数据:将原数据与计算出的CRC校验码拼接起来,形成最终的发送帧:原数据 + CRC码。
举例演示 (CRC-3)
原始数据:1101 (二进制)
生成多项式 G(x):1011 (对应 x^3 + x + 1, 最高次幂 r=3)
计算CRC码的步骤:
1、补3个0:数据后面加3个0 → 1101 000
2、模2除法:用 1101000 除以 1011(只做异或运算)
bash
1 0 0 1 (商,这里不关心)
__________
1011 ) 1 1 0 1 0 0 0
1 0 1 1
-------
1 1 0 0 (余数拖下一位0)
1 0 1 1
-------
1 1 1 0 (余数拖下一位0)
1 0 1 1
-------
1 0 1 0 (余数拖下一位0)
1 0 1 1
-------
0 0 1 (最终余数)
3、得到余数:001。这就是CRC-3校验码(r=3位)。
4、发送数据:1101 + 001 = 1101001。
接收方校验:
接收方收到 1101001,使用同一个生成多项式 1011 去除它(同样做模2除法)。如果余数为 000,则说明数据在传输中没有出错;如果余数非0,则说明发生了错误。
bash
1 0 0 1
__________
1011 ) 1 1 0 1 0 0 1
1 0 1 1
-------
1 1 0 0
1 0 1 1
-------
1 1 1 0
1 0 1 1
-------
1 0 1 1
1 0 1 1
-------
0 0 0 (余数为0,校验通过)
CRC的检错能力
CRC的检错能力与生成多项式的设计密切相关。一个设计良好的CRC多项式可以保证检测出:
所有奇数个错误(前提是多项式包含因子 (x+1))
所有双比特错误
所有长度 ≤ r 的突发错误(连续的一段错误)
长度 = r+1 的突发错误,漏检概率为 1/2^(r-1)
长度 > r+1 的突发错误,漏检概率为 1/2^r
硬件实现与软件计算
硬件实现:非常高效。可以使用带有反馈移位的线性反馈移位寄存器(LFSR) 来实现。每一位时钟周期处理一个输入位,结构极其简单。
做FPGA的伙伴可以学习,做软件的了解即可。博主也只是略微扫了一眼。
推荐文章:
软件实现:
1、直接计算法(慢):模拟上述除法过程,一位一位处理。
2、查表法(快):预先计算好所有256个字节的CRC值(因为一个字节有8位),然后对数据进行循环查表计算。这是目前最主流的软件CRC实现方式,速度很快。
推荐文章:
CRC校验C语言实现-CRC8、CRC16、CRC16的直接计算法、查表法
常见应用与标准

一些注意事项
1、不是纠错码:CRC主要用于检测错误,虽然理论上可以纠错,但在实践中通常只用于检测。发现错误后,一般会请求对方重传数据。
2、初值和异或值:许多实际标准会对CRC寄存器设置一个初始值(比如全1),并在计算结束后对结果异或一个固定值(如全1),以增强鲁棒性。这可以防止漏检数据开头的额外0。
3、输入/输出反转:有些协议(如以太网CRC-32)要求输入数据的每个字节比特顺序反转,或最终CRC值的字节顺序反转。这在实现时需要特别注意。