CRC的数学原理

文章目录

    • [Part 1. CRC概述](#Part 1. CRC概述)
    • [Part 2. CRC(循环冗余校验)的有效性证明](#Part 2. CRC(循环冗余校验)的有效性证明)
      • [1. 定义核心多项式](#1. 定义核心多项式)
      • [2. 发送方的编码过程推导](#2. 发送方的编码过程推导)
      • [3. 接收方的校验过程证明](#3. 接收方的校验过程证明)
        • [情况1:数据无差错, T ′ ( x ) = T ( x ) T'(x)=T(x) T′(x)=T(x)](#情况1:数据无差错, T ′ ( x ) = T ( x ) T'(x)=T(x) T′(x)=T(x))
        • [情况2:数据有差错, T ′ ( x ) = T ( x ) + E ( x ) T'(x)=T(x)+E(x) T′(x)=T(x)+E(x)](#情况2:数据有差错, T ′ ( x ) = T ( x ) + E ( x ) T'(x)=T(x)+E(x) T′(x)=T(x)+E(x))
      • [4. CRC检错能力的补充证明](#4. CRC检错能力的补充证明)
      • 总结
    • [Part 3. CRC漏检概率的证明](#Part 3. CRC漏检概率的证明)
      • [1. 前提:随机错误模型假设](#1. 前提:随机错误模型假设)
      • [2. 漏检的充要条件](#2. 漏检的充要条件)
      • [3. 概率推导:为什么漏检概率是 1 / 2 r 1/2^r 1/2r](#3. 概率推导:为什么漏检概率是 1 / 2 r 1/2^r 1/2r)
      • [4. 关键补充:为什么实际漏检概率极低](#4. 关键补充:为什么实际漏检概率极低)
      • 总结
    • [Part 4. CRC-16 的C语言实现](#Part 4. CRC-16 的C语言实现)

CRC (Cyclic Redundancy Check,循环冗余校验)是一种 基于多项式除法的差错检测技术 ,广泛应用于数据传输和存储场景(如网络通信、磁盘存储、串口传输等),用于判断数据在传输或存储过程中是否发生了比特翻转等错误。

Part 1. CRC概述

核心原理

CRC的本质是将数据看作二进制多项式,通过模2除法计算余数,将余数作为校验码附加到原始数据后。接收方对包含校验码的完整数据重复相同的计算,如果余数为0,则判定数据无错;否则判定数据出错。

关键概念
  1. 原始数据 :待传输的二进制序列,对应多项式 D ( x ) D(x) D(x)。
  2. 生成多项式 :预先约定的固定二进制序列,对应多项式 G ( x ) G(x) G(x),是CRC的核心参数(如CRC-32的生成多项式为 x 32 + x 26 + x 23 + x 22 + x 16 + x 12 + x 11 + x 10 + x 8 + x 7 + x 5 + x 4 + x 2 + x + 1 x^{32}+x^{26}+x^{23}+x^{22}+x^{16}+x^{12}+x^{11}+x^{10}+x^8+x^7+x^5+x^4+x^2+x+1 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1)。
  3. 校验码(CRC码) :原始数据左移 r r r 位( r r r 是生成多项式的阶数,即最高次幂)后,除以生成多项式得到的余数,长度为 r r r 位。
计算步骤(发送方)
  1. 设生成多项式 G ( x ) G(x) G(x) 的阶数为 r r r,将原始数据 D ( x ) D(x) D(x) 左移 r r r 位,得到 D ′ ( x ) = D ( x ) × x r D'(x) = D(x) \times x^r D′(x)=D(x)×xr(相当于在原始数据末尾补 r r r 个0)。
  2. 对 D ′ ( x ) D'(x) D′(x) 与 G ( x ) G(x) G(x) 进行模2除法 (模2运算规则:加法无进位,减法无借位,即 0 + 0 = 0 , 0 + 1 = 1 , 1 + 0 = 1 , 1 + 1 = 0 0+0=0, 0+1=1, 1+0=1, 1+1=0 0+0=0,0+1=1,1+0=1,1+1=0)。
  3. 得到余数 R ( x ) R(x) R(x),其长度为 r r r 位(不足补0),这就是CRC校验码。
  4. 将校验码附加到原始数据末尾,得到传输数据 T ( x ) = D ( x ) × x r + R ( x ) T(x) = D(x) \times x^r + R(x) T(x)=D(x)×xr+R(x)。
校验步骤(接收方)
  1. 接收传输数据 T ( x ) T(x) T(x)。
  2. 对 T ( x ) T(x) T(x) 与生成多项式 G ( x ) G(x) G(x) 进行模2除法。
  3. 若余数为0 → 数据无错;若余数不为0 → 数据出错。

常见CRC标准

不同的生成多项式对应不同的CRC标准,适用于不同场景:

标准 生成多项式(二进制) 特点 应用场景
CRC-8 100000111 100000111 100000111( x 8 + x 2 + x + 1 x^8+x^2+x+1 x8+x2+x+1) 短校验码,计算快 小数据块校验
CRC-16 10001000000100001 10001000000100001 10001000000100001( x 16 + x 15 + x 2 + 1 x^{16}+x^{15}+x^2+1 x16+x15+x2+1) 经典标准,兼容性好 串口通信、Modbus
CRC-32 32位标准多项式(见上文) 高检错率,抗干扰强 以太网、ZIP、磁盘

核心特点

  1. 检错能力强
    • 可以检测出所有奇数个比特错误
    • 可以检测出所有长度小于等于生成多项式阶数的突发错误(突发错误指连续多个比特翻转)。
    • 对长度大于阶数的突发错误,检错概率约为 1 − 2 − r 1 - 2^{-r} 1−2−r( r r r 为校验码长度),CRC-32的检错概率接近100%。
  2. 计算高效
    • 可以通过硬件电路(移位寄存器)或软件算法快速实现,适合实时系统。
  3. 局限性
    • 仅能检错,不能纠错:发现错误后,只能要求重传,无法直接修正错误比特。
    • 存在极小概率的"漏检":不同的原始数据可能生成相同的CRC码,导致错误未被检测到(概率极低,可忽略)。

典型应用场景

  • 网络通信:以太网帧、TCP/UDP数据包的校验。
  • 存储系统:磁盘扇区、光盘数据、压缩文件(ZIP、RAR)的校验。
  • 嵌入式通信:串口、CAN总线、SPI等协议的数据校验。

与其他校验方式的对比

校验方式 原理 检错能力 适用场景
CRC 多项式模2除法 强(可检测多类错误) 实时传输、存储
奇偶校验 统计1的个数的奇偶性 弱(仅检测奇数个错误) 简单低成本场景
校验和 字节累加求和取模 中等 网络协议(如IP头校验)

Part 2. CRC(循环冗余校验)的有效性证明

要证明 CRC(循环冗余校验)的正确性 ,核心是证明:接收方对无差错的传输数据执行模2除法时,余数必然为0;若余数不为0,则数据一定存在差错

证明过程基于多项式模2运算的代数性质,以下是严谨的推导步骤:

1. 定义核心多项式

首先明确发送方和接收方约定的关键参数:

  • 设原始数据对应的二进制多项式为 D ( x ) D(x) D(x),长度为 k k k 位。
  • 设生成多项式为 G ( x ) G(x) G(x),阶数为 r r r(即最高次项为 x r x^r xr),长度为 r + 1 r+1 r+1 位。
  • 模2运算规则:加法/减法无进位/借位,满足 a + a = 0 a+a=0 a+a=0, a − a = 0 a-a=0 a−a=0,等价于异或运算

2. 发送方的编码过程推导

发送方的编码步骤对应多项式运算:

  1. 原始数据左移 r r r 位,等价于多项式乘以 x r x^r xr,得到:
    D ′ ( x ) = D ( x ) ⋅ x r D'(x) = D(x) \cdot x^r D′(x)=D(x)⋅xr

    这一步的目的是为校验码预留 r r r 位空间。

  2. 对 D ′ ( x ) D'(x) D′(x) 执行模2除法 D ′ ( x ) ÷ G ( x ) D'(x) \div G(x) D′(x)÷G(x),根据多项式除法性质,可分解为:
    D ′ ( x ) = Q ( x ) ⋅ G ( x ) + R ( x ) D'(x) = Q(x) \cdot G(x) + R(x) D′(x)=Q(x)⋅G(x)+R(x)

    其中:

    • Q ( x ) Q(x) Q(x) 是商多项式;
    • R ( x ) R(x) R(x) 是余数多项式,且 deg ( R ( x ) ) < r \text{deg}(R(x)) < r deg(R(x))<r(余数的阶数一定小于除数的阶数),因此 R ( x ) R(x) R(x) 对应一个 r r r 位二进制数,即 CRC校验码
  3. 发送方将校验码附加到原始数据后,最终传输的多项式为:
    T ( x ) = D ′ ( x ) + R ( x ) T(x) = D'(x) + R(x) T(x)=D′(x)+R(x)

    代入上式可得:
    T ( x ) = Q ( x ) ⋅ G ( x ) + R ( x ) + R ( x ) T(x) = Q(x) \cdot G(x) + R(x) + R(x) T(x)=Q(x)⋅G(x)+R(x)+R(x)

    根据模2运算性质 R ( x ) + R ( x ) = 0 R(x)+R(x)=0 R(x)+R(x)=0,因此:
    T ( x ) = Q ( x ) ⋅ G ( x ) \boldsymbol{T(x) = Q(x) \cdot G(x)} T(x)=Q(x)⋅G(x)

    这是CRC正确性的核心等式传输多项式 T ( x ) T(x) T(x) 是生成多项式 G ( x ) G(x) G(x) 的整数倍

3. 接收方的校验过程证明

接收方收到数据后,得到多项式 T ′ ( x ) T'(x) T′(x),分两种情况讨论:

情况1:数据无差错, T ′ ( x ) = T ( x ) T'(x)=T(x) T′(x)=T(x)

此时代入核心等式:
T ′ ( x ) = Q ( x ) ⋅ G ( x ) T'(x) = Q(x) \cdot G(x) T′(x)=Q(x)⋅G(x)

接收方执行模2除法 T ′ ( x ) ÷ G ( x ) T'(x) \div G(x) T′(x)÷G(x),余数为:
Remainder [ T ′ ( x ) / G ( x ) ] = Remainder [ Q ( x ) ⋅ G ( x ) / G ( x ) ] = 0 \text{Remainder}[T'(x)/G(x)] = \text{Remainder}[Q(x)\cdot G(x)/G(x)] = 0 Remainder[T′(x)/G(x)]=Remainder[Q(x)⋅G(x)/G(x)]=0
结论:无差错时,余数必然为0。

情况2:数据有差错, T ′ ( x ) = T ( x ) + E ( x ) T'(x)=T(x)+E(x) T′(x)=T(x)+E(x)

其中 E ( x ) ≠ 0 E(x) \neq 0 E(x)=0 是错误多项式 ,对应数据中比特翻转的位置。

此时接收方计算的余数为:
Remainder [ T ′ ( x ) / G ( x ) ] = Remainder [ ( T ( x ) + E ( x ) ) / G ( x ) ] \text{Remainder}[T'(x)/G(x)] = \text{Remainder}[(T(x)+E(x))/G(x)] Remainder[T′(x)/G(x)]=Remainder[(T(x)+E(x))/G(x)]

代入 T ( x ) = Q ( x ) ⋅ G ( x ) T(x)=Q(x)\cdot G(x) T(x)=Q(x)⋅G(x),可得:
Remainder [ ( Q ( x ) ⋅ G ( x ) + E ( x ) ) / G ( x ) ] = Remainder [ E ( x ) / G ( x ) ] \text{Remainder}[(Q(x)\cdot G(x)+E(x))/G(x)] = \text{Remainder}[E(x)/G(x)] Remainder[(Q(x)⋅G(x)+E(x))/G(x)]=Remainder[E(x)/G(x)]

  • 若 Remainder [ E ( x ) / G ( x ) ] ≠ 0 \text{Remainder}[E(x)/G(x)] \neq 0 Remainder[E(x)/G(x)]=0,则余数不为0,接收方判定数据出错。
  • 若 Remainder [ E ( x ) / G ( x ) ] = 0 \text{Remainder}[E(x)/G(x)] = 0 Remainder[E(x)/G(x)]=0,则 E ( x ) E(x) E(x) 是 G ( x ) G(x) G(x) 的倍数,此时会发生漏检 ,但这种情况的概率极低( 1 / 2 r 1/2^r 1/2r),且可通过选择合适的 G ( x ) G(x) G(x) 进一步降低概率。

4. CRC检错能力的补充证明

CRC的强检错能力也可通过多项式性质证明,以两个典型结论为例:

  1. 检测所有奇数个比特错误

    奇数个比特错误对应的错误多项式 E ( x ) E(x) E(x) 有奇数个非零项。

    若生成多项式 G ( x ) G(x) G(x) 包含因子 ( x + 1 ) (x+1) (x+1)(即 G ( 1 ) = 0 G(1)=0 G(1)=0,模2运算下 1 + 1 = 0 1+1=0 1+1=0),则 E ( 1 ) = 1 E(1)=1 E(1)=1(奇数个1相加为1),因此 E ( x ) E(x) E(x) 不能被 G ( x ) G(x) G(x) 整除,余数不为0,错误可被检测。

  2. 检测所有长度 ≤ r \le r ≤r 的突发错误

    突发错误是指连续 b b b 位比特翻转,对应的多项式为 E ( x ) = x i ( 1 + x + x 2 + ⋯ + x b − 1 ) E(x)=x^i(1+x+x^2+\dots+x^{b-1}) E(x)=xi(1+x+x2+⋯+xb−1),长度 b ≤ r b \le r b≤r。

    由于 deg ( E ( x ) ) = i + b − 1 \text{deg}(E(x))=i+b-1 deg(E(x))=i+b−1,且 G ( x ) G(x) G(x) 阶数为 r r r, b ≤ r b \le r b≤r 时 E ( x ) E(x) E(x) 的最高次项小于 G ( x ) G(x) G(x) 的最高次项,无法被 G ( x ) G(x) G(x) 整除,余数不为0,错误可被检测。

总结

CRC的正确性本质是多项式模2运算的整除性

  • 无差错时,传输多项式是生成多项式的倍数 → 余数为0;
  • 有差错时,错误多项式大概率不是生成多项式的倍数 → 余数不为0。

Part 3. CRC漏检概率的证明

CRC 漏检概率的核心,其完整表述是:当错误多项式 E ( x ) E(x) E(x) 是生成多项式 G ( x ) G(x) G(x) 的倍数时,CRC 会发生漏检,且在随机错误模型下,漏检的概率约为 1 / 2 r 1/2^r 1/2r ( r r r 是生成多项式 G ( x ) G(x) G(x) 的阶数,即 CRC 校验码的长度)。

下面我们从错误模型、多项式整除性、概率推导三个层面,严谨证明这个结论:

1. 前提:随机错误模型假设

漏检概率的计算基于一个合理的工程假设:

  • 数据在传输过程中,每个比特发生翻转的概率是独立的,且错误模式是随机分布的。
  • 错误多项式 E ( x ) E(x) E(x) 的每一项系数(对应比特是否翻转)是 0 或 1 的随机变量,所有可能的 E ( x ) E(x) E(x) 出现的概率均等。

2. 漏检的充要条件

根据之前的 CRC 正确性证明,接收方计算的余数为:
Remainder [ T ′ ( x ) / G ( x ) ] = Remainder [ E ( x ) / G ( x ) ] \text{Remainder}[T'(x)/G(x)] = \text{Remainder}[E(x)/G(x)] Remainder[T′(x)/G(x)]=Remainder[E(x)/G(x)]

漏检发生的充要条件是:
Remainder [ E ( x ) / G ( x ) ] = 0 \text{Remainder}[E(x)/G(x)] = 0 Remainder[E(x)/G(x)]=0

等价于:
E ( x ) = K ( x ) ⋅ G ( x ) E(x) = K(x) \cdot G(x) E(x)=K(x)⋅G(x)

其中 K ( x ) K(x) K(x) 是任意非零多项式。也就是说,只有当错误模式恰好对应 G ( x ) G(x) G(x) 的某个倍数时,才会漏检

3. 概率推导:为什么漏检概率是 1 / 2 r 1/2^r 1/2r

我们可以从余数空间的大小错误多项式的分布两个角度分析:

  1. 余数空间的大小

    对于阶数为 r r r 的生成多项式 G ( x ) G(x) G(x),任何多项式除以 G ( x ) G(x) G(x) 得到的余数 R ( x ) R(x) R(x) 满足:
    deg ( R ( x ) ) < r \text{deg}(R(x)) < r deg(R(x))<r

    因此余数 R ( x ) R(x) R(x) 对应的二进制序列长度为 r r r 位,总共有 2 r 2^r 2r 种可能的余数(从 000 ⋯ 0 000\cdots0 000⋯0 到 111 ⋯ 1 111\cdots1 111⋯1)。

  2. 随机错误下的余数分布

    在随机错误模型中,错误多项式 E ( x ) E(x) E(x) 是完全随机的,因此它除以 G ( x ) G(x) G(x) 得到的余数也是均匀分布 在 2 r 2^r 2r 种可能中的。

    • 余数为 0 0 0 的情况,恰好对应漏检场景,仅占 1 1 1 种。
    • 其余 2 r − 1 2^r-1 2r−1 种余数均会被检测到。
  3. 最终概率计算

    漏检概率 = (余数为 0 的情况数) / (总余数情况数) = 1 2 r \frac{1}{2^r} 2r1

4. 关键补充:为什么实际漏检概率极低

  • 对于 CRC-32( r = 32 r=32 r=32),漏检概率为 1 / 2 32 ≈ 2.3 × 1 0 − 10 1/2^{32} \approx 2.3 \times 10^{-10} 1/232≈2.3×10−10,这是一个几乎可以忽略的极小值。
  • 工程中选择的生成多项式(如 CRC-32 标准多项式)还会额外满足一些性质(比如包含因子 x + 1 x+1 x+1),可以进一步排除特定类型的错误(如奇数个比特错误),让实际漏检概率比理论值更低。

总结

CRC 漏检的本质是错误多项式恰好是生成多项式的倍数 ,在随机错误模型下,由于余数均匀分布在 2 r 2^r 2r 种可能中,因此漏检概率为 1 / 2 r 1/2^r 1/2r,且 r r r 越大(校验码越长),漏检概率越低。


Part 4. CRC-16 的C语言实现

以下是 CRC-16(标准多项式:0x8005,对应 x 16 + x 15 + x 2 + 1 x^{16}+x^{15}+x^2+1 x16+x15+x2+1)的C语言实现,包含「逐位计算法」和「查表优化法」两种核心方式(前者直观易懂,后者效率更高),并附带详细注释和测试用例,帮助理解CRC的计算过程。

一、CRC-16 核心参数说明

  • 生成多项式: G ( x ) = x 16 + x 15 + x 2 + 1 G(x) = x^{16} + x^{15} + x^2 + 1 G(x)=x16+x15+x2+1 → 二进制 1000000000000101 → 十六进制 0x8005
  • 校验码长度: r = 16 r=16 r=16 位(2字节)
  • 初始值:0xFFFF(常见约定,也可根据协议调整为 0x0000
  • 异或输出:0xFFFF(最终结果需与该值异或,部分协议可能为 0x0000
  • 运算规则:高位优先(MSB First)

二、实现代码(含两种方法+测试用例)

c 复制代码
#include <stdint.h>
#include <stdio.h>
#include <string.h>

// -------------------------- 方法1:逐位计算法(直观易懂,适合理解原理)--------------------------
/**
 * @brief  CRC-16 逐位计算(高位优先)
 * @param  data: 待校验的原始数据
 * @param  len:  原始数据长度(字节数)
 * @return 16位CRC校验码(uint16_t)
 */
uint16_t crc16_bitwise(const uint8_t *data, uint32_t len) {
    const uint16_t poly = 0x8005;  // 生成多项式 G(x) = x^16 + x^15 + x^2 + 1
    uint16_t crc = 0xFFFF;         // 初始值(约定值)

    // 1. 遍历每一个字节(原始数据的所有字节)
    for (uint32_t i = 0; i < len; i++) {
        // 2. 将当前字节与CRC的高8位异或(CRC共16位,高8位是 crc >> 8)
        crc ^= (uint16_t)(data[i] << 8);  // 左移8位,对齐CRC高8位

        // 3. 遍历当前字节的每一位(8位)
        for (uint8_t j = 0; j < 8; j++) {
            // 4. 判断CRC最高位是否为1:若为1,左移后异或多项式;若为0,仅左移
            if (crc & 0x8000) {  // 0x8000 是 16位的最高位(第15位)
                crc = (crc << 1) ^ poly;
            } else {
                crc <<= 1;  // 最高位为0,左移后无需异或
            }
        }
    }

    // 5. 最终结果与 0xFFFF 异或(约定输出处理)
    return crc ^ 0xFFFF;
}

// -------------------------- 方法2:查表优化法(效率更高,工程常用)--------------------------
// 步骤1:预生成CRC-16 查找表(256个值,对应0~255每个字节的CRC结果)
static uint16_t crc16_table[256] = {0};

/**
 * @brief  预生成CRC-16查找表(程序启动时调用1次即可)
 */
void crc16_init_table(void) {
    const uint16_t poly = 0x8005;
    // 遍历0~255所有可能的字节值
    for (uint16_t i = 0; i < 256; i++) {
        uint16_t crc = i << 8;  // 对齐16位CRC的高8位
        // 逐位计算当前字节的CRC值,存入表中
        for (uint8_t j = 0; j < 8; j++) {
            if (crc & 0x8000) {
                crc = (crc << 1) ^ poly;
            } else {
                crc <<= 1;
            }
        }
        crc16_table[i] = crc;
    }
}

/**
 * @brief  CRC-16 查表计算(高位优先,效率是逐位法的8倍)
 * @param  data: 待校验的原始数据
 * @param  len:  原始数据长度(字节数)
 * @return 16位CRC校验码(uint16_t)
 */
uint16_t crc16_table_lookup(const uint8_t *data, uint32_t len) {
    uint16_t crc = 0xFFFF;  // 初始值

    for (uint32_t i = 0; i < len; i++) {
        // 核心:用当前字节与CRC高8位异或,作为查表索引,再更新CRC
        crc = (crc << 8) ^ crc16_table[(crc >> 8) ^ data[i]];
    }

    return crc ^ 0xFFFF;  // 最终异或输出
}

// -------------------------- 测试用例 --------------------------
int main(void) {
    // 测试数据1:"123456789"(CRC-16标准测试数据,预期结果:0xBB3D)
    const uint8_t test_data1[] = "123456789";
    uint32_t len1 = strlen((const char *)test_data1);

    // 测试数据2:自定义数据(如0x01, 0x02, 0x03),可自行验证
    const uint8_t test_data2[] = {0x01, 0x02, 0x03, 0x04, 0x05};
    uint32_t len2 = sizeof(test_data2) / sizeof(test_data2[0]);

    // 初始化查找表(仅需1次)
    crc16_init_table();

    // 方法1:逐位计算测试
    uint16_t crc1 = crc16_bitwise(test_data1, len1);
    uint16_t crc3 = crc16_bitwise(test_data2, len2);

    // 方法2:查表计算测试
    uint16_t crc2 = crc16_table_lookup(test_data1, len1);
    uint16_t crc4 = crc16_table_lookup(test_data2, len2);

    // 输出结果
    printf("=== CRC-16 测试结果 ===\n");
    printf("测试数据1:%s\n", test_data1);
    printf("逐位计算结果:0x%04X(预期:0xBB3D)\n", crc1);
    printf("查表计算结果:0x%04X(预期:0xBB3D)\n\n", crc2);

    printf("测试数据2:0x01, 0x02, 0x03, 0x04, 0x05\n");
    printf("逐位计算结果:0x%04X\n", crc3);
    printf("查表计算结果:0x%04X\n", crc4);

    return 0;
}

三、代码核心逻辑解释(对应CRC原理)

1. 逐位计算法(重点理解)

完全对应之前讲的「多项式模2除法」,每一步都能映射到代数运算:

  • 初始值 0xFFFF:相当于模2除法的「初始余数」(约定值,可调整)。
  • crc ^= (data[i] << 8):将当前字节(8位)与CRC的高8位异或,对应「多项式相加」(模2运算)。
  • 判断最高位 crc & 0x8000:对应模2除法中「除数(生成多项式)与被除数最高位对齐」,若被除数最高位为1,则减去除数(异或多项式)。
  • 左移操作 crc << 1 :对应模2除法的「被除数右移一位」(等价于多项式乘以 x x x)。
  • 最终异或 0xFFFF:是CRC的约定输出处理,目的是避免全0数据的CRC结果为0(可选,部分协议无此步骤)。
2. 查表优化法(工程实用)
  • 核心思想:预先生成「0~255每个字节对应的CRC中间结果」(存在crc16_table中),计算时直接查表,无需逐位循环,效率提升8倍(因为每个字节少了8次位运算)。
  • 查表公式 crc = (crc << 8) ^ crc16_table[(crc >> 8) ^ data[i]]
    1. crc << 8:CRC左移8位,腾出低8位空间。
    2. (crc >> 8) ^ data[i]:用CRC的高8位与当前字节异或,得到查表索引(0~255)。
    3. 异或查表结果:快速得到当前字节的CRC贡献值,更新CRC。

四、测试结果验证

编译运行代码后,输出应满足:

  • 标准测试数据 "123456789" 的CRC-16结果固定为 0xBB3D(行业通用验证值),说明代码正确。
  • 逐位法和查表法结果完全一致,证明两种实现等价。

五、灵活调整(适配不同协议)

如果需要适配其他CRC-16变种(如Modbus-RTU、CCITT),只需修改3个参数:

协议 生成多项式 初始值 异或输出
标准CRC-16 0x8005 0xFFFF 0xFFFF
Modbus-RTU 0x8005 0xFFFF 0x0000
CRC-16-CCITT 0x1021 0x0000 0x0000

例如,若要实现Modbus-RTU的CRC-16,只需将代码中 return crc ^ 0xFFFF 改为 return crc ^ 0x0000 即可。

通过这段代码,可以直观看到:CRC的计算本质是「基于约定规则的位运算循环」,完全遵循多项式模2除法的代数逻辑。

相关推荐
十五年专注C++开发2 小时前
ZeroMQ: 一款高性能、异步、轻量级的消息传输库
网络·c++·分布式·zeroqm
晚风(●•σ )3 小时前
【华为 ICT & HCIA & eNSP 习题汇总】——题目集25
网络·计算机网络·交换机
乾元3 小时前
用 AI 做联动:当应用层出现问题,网络如何被“自动拉入决策回路”
运维·开发语言·网络·人工智能·ci/cd·自动化
金灰3 小时前
一带一路(金砖)--网络安全防护治理赛项
网络·计算机网络·安全·web安全·网络安全·网络攻击模型·安全威胁分析
Bruce_Liuxiaowei3 小时前
网站敏感文件_目录大全(分类记忆+风险标注)
运维·网络·网络协议·http·网络安全·https
脆皮瞎4 小时前
内网域渗透-信息收集
网络·网络安全
老猿讲编程4 小时前
【车载信息安全系列1】车载Linux系统常用的OpenSSL, HSE加密工作原理
linux·网络
饱饱要坚持可持续发展观4 小时前
Linux 防火墙开放/限制端口
linux·运维·网络
哈利路亚胡辣汤4 小时前
访问网页的全过程
网络·面试