CRC 循环冗余校验

互动教程 — 从零理解数据校验的核心算法

0 开始前:你需要知道的

如果你已经熟悉二进制,可以跳过这一节。

什么是二进制?

我们日常用十进制(0-9),但计算机只认识二进制——只有 0 和 1 两个数字。每个 0 或 1 叫做一个 bit(比特/位)。

十进制: 0 1 2 3 4 5 6 7 二进制: 000 001 010 011 100 101 110 111

什么是"运算"?

对数字做一些规则操作。比如加法是运算,XOR 也是一种运算——下面马上会讲。

什么是"幂次"?

就是 x 的几次方。x¹ = x,x² = x×x,x³ = x×x×x。在 CRC 里,幂次对应二进制中从右往左数的位置(从0开始)。

x⁴ + x + 1 对应二进制(从高位到低位): 位置: 4 3 2 1 0 1 0 0 1 1 ← 有这项就写1,没有就写0

1 CRC 是什么?

CRC(Cyclic Redundancy Check)是一种错误检测技术。发送方在数据后面附加一段校验码,接收方通过同样的计算来判断数据是否在传输中出错。

类比:想象你在寄快递。你把物品(数据)放进箱子,然后用一把特殊的锁(CRC 算法)锁上。收件人收到后,用同一把锁验证——如果箱子被打开过或物品被调换,锁的校验就会不匹配。

核心思想很简单:

数据 ÷ 约定好的除数 = 商 ... 余数(就是 CRC 校验码)

但这个"除法"不是普通除法,而是用 XOR(异或)运算代替减法的特殊除法。下面两节会分别讲 XOR 和这种特殊除法。

2 先搞懂 XOR(异或)

XOR 是 CRC 的基础运算。规则极其简单:相同为0,不同为1。

ABA XOR B
000
011
101
110

对多bit数据,逐位做 XOR:

1 1 0 1 XOR 1 0 1 1 ───────── 0 1 1 0

逐位看:1 XOR 1 = 0,1 XOR 0 = 1,0 XOR 1 = 1,1 XOR 1 = 0

记住 XOR 的一个关键特性:
A XOR B XOR B = A(同一个数 XOR 两次,等于没 XOR)
这个特性后面验证数据时会用到。

3 什么是"模2除法"?

你小时候学过的长除法是这样的:

普通除法: 110101 ÷ 10011 每一步用"减法"消掉最高位,有借位等问题...

模2除法和普通长除法几乎一样,唯一的区别:用 XOR 代替减法。

普通除法模2除法(CRC用)
每一步操作减法XOR
借位/进位有没有!
只看最高位需要比较大小最高位是1就对上去

模2除法的规则(只有3条):

规则1 看被除数当前最高位,如果是 1,就把除数对齐到这里

规则2 对齐后,逐位做 XOR

规则3 XOR 结果的最高位一定是 0(因为 1 XOR 1 = 0),然后往右看下一个 1,重复

一句话总结:看到1就对上去XOR,XOR完最高位变0,往右移找下一个1,直到处理完所有位。剩下的就是余数。

4 生成多项式详解

多项式就是模2除法里的除数。它决定了"用什么去除"。

多项式的两种写法:

写法1:代数形式

x⁴ + x + 1

意思是:第4位、第1位、第0位是1,其余是0。

写法2:二进制形式(实际计算用这个)

幂次: 4 3 2 1 0 系数: 1 0 0 1 1 → 10011
转换规则(记住这3点就够了):
• 最高幂次 = CRC的位数(x⁴ → CRC-4 → 余数4位)
• 二进制位数 = 幂次 + 1(x⁴ → 5位二进制除数)
• 代数式里有的幂次 → 对应位写1,没有 → 写0

常见标准多项式:

名称代数形式二进制应用场景
CRC-4-ITUx⁴ + x + 110011电信
CRC-8x⁸ + x² + x + 1100000111蓝牙、I2C
CRC-16-USBx¹⁶ + x¹⁵ + x² + 111000000000000101USB
CRC-32x³² + x²⁶ + ... + 1(很长)以太网、ZIP、PNG

实际开发中怎么选?

你不需要自己发明多项式,查规范就行:

互动:多项式转换器

输入幂次(如 4,1,0 表示 x⁴+x¹+x⁰),看对应的二进制:

5 完整手算示例

发送数据 110101,用 CRC-4 多项式 10011(x⁴+x+1)。

第1步 数据末尾补 4 个 0(CRC-4 → 补4位)

110101 → 1101010000

第2步 做模2除法(下面逐步展示)

10011)1101010000 ← 被除数(数据+补零)
10011 ← 第1位是1,对上去 XOR
─────
10010 ← XOR结果: 11010 XOR 10011 = 01001,去掉前导0 → 1001
10011 ← 当前最高位是1,再对上去 XOR
─────
00011 ← XOR结果: 10010 XOR 10011 = 00001 → 1
11 ← 前面都是0,跳过,直到看到1
──
... ← 继续,直到处理完所有位
最终余数: ???? ← 最后4位就是CRC校验码

上面只是示意。下面是真正的逐步计算(和互动计算器结果一致):

被除数: 1 1 0 1 0 1 0 0 0 0 除数: 10011
10011 ← 位置0: 看到1,XOR
───────────────────
0100110000 ← 结果,前导0跳过
10011 ← 位置1: 看到1,XOR
──────────────────
000000000 ← 结果全是0!
后面全是0,不用再除了。
余数 = 0000
等等,余数是 0000?
是的,对于数据 110101 和多项式 10011,余数恰好是 0000。这不代表算法有问题——只是这组数据碰巧"整除"了。换一个数据试试,比如 101101,你就会得到非零余数。去下面的互动计算器试试吧!

第3步 拼接发送

最终发送: 110101 + 0000 = 1101010000

接收方收到后,用同样的多项式去除,如果余数为0就说明数据没问题。

6 动手试试!

输入数据和多项式,看 CRC 是怎么一步步算出来的。

7 验证:点击翻转位来模拟传输错误

下面是上一步算出的完整数据。点击任意一个 bit 可以翻转它(0变1,1变0),模拟传输中出错:

■ 原始数据   ■ CRC校验码   ■ 被翻转的位(已出错)
试试看:
1. 先点"验证数据" → 余数为0,通过
2. 点击翻转任意一个 bit → 再验证 → 余数不为0,检测到错误!
3. 翻转两个 bit → 验证 → 有些多项式也能检测到!
4. 思考:有没有翻转后余数还是0的情况?(这就是为什么需要选择好的多项式)

8 总结 & 实际应用

回顾整个流程:

发送方: 数据 ──→ 补零 ──→ 模2除法 ──→ 余数(CRC) ──→ 数据+CRC 发出去 │ ↓ 接收方: 收到数据+CRC ──→ 用同样的多项式做模2除法 ──→ 余数=0? 通过! ──→ 余数≠0? 出错了!

实际应用中的 CRC:

场景常用多项式CRC 位数
以太网CRC-3232
ZIP / PNGCRC-3232
USBCRC-5 / CRC-165 / 16
串口通信CRC-16-MODBUS16
为什么 CRC 能检测错误?
因为合法的"数据+CRC"组合一定能被多项式整除(余数为0)。传输中任何一位出错,接收方再除就会有余数。不同多项式的检测能力不同——位数越高,能检测的错误越多。CRC-32 能检测出 99.99% 以上的错误。