利用C++实现CRC校验
前言
一、CRC校验用途
1.1 通信协议与数据传输
1.2 存储设备
1.3 工业控制与嵌入式系统
1.4 软件与文件完整性
1.5 科学计算 & 深空探测
小结
二、CRC校验原理
2.1 CRC 的校验本质
2.2 CRC 校验的核心步骤
(1)选择 CRC 生成多项式
(2)发送端计算 CRC 码
(3)接收端校验
2.3 CRC 二进制除法示例
三、CRC校验代码实现步骤
1.选择合适的多项式
2. 初始化 CRC 寄存器
3. 预处理数据
4. 逐位计算 CRC
5. 后处理 CRC
6. 输出 CRC 校验码
四、CRC校验代码(以CRC-4为例)
五、总结
前言
CRC校验可以作为c++学习过程中的小项目,帮助我们更好的将c++学习中的理论知识和实践相结合,本项目中的CRC校验代码,涉及基础语法、位运算、条件判断、循环控制、函数、类型转换等。本篇文章从CRC校验的用途、CRC校验代码实现原理、CRC校验代码三方面展开。
一、CRC校验用途
CRC(循环冗余校验,Cyclic Redundancy Check)是一种高效的错误检测技术,它的主要作用是检测数据传输或存储过程中可能发生的错误,确保数据的完整性。下面介绍 CRC 在各个领域的实际用途。
1.1 通信协议与数据传输
- 网络通信:在 以太网 (Ethernet)、Wi-Fi 等协议中,数据包都会附带 CRC 校验码,接收端对其进行计算并校验数据是否完整。如果 CRC 校验失败,则表示数据包在传输过程中出现错误,需要 请求重传 (ARQ) 或 丢弃错误数据。以太网 (Ethernet)主要使用CRC-32检测数据帧中的错误。
- 无线通信:在无线环境下,数据容易受 信号干扰、噪声、抖动 等影响,因此 CRC 被用于数据包的错误检测。5G NR(New Radio) 使用 CRC-24 进行数据完整性校验,以减少误码率。蓝牙 (Bluetooth)、ZigBee、LoRa 等无线通信协议中,通常使用 CRC-8 或 CRC-16进行校验。
- 数据链路层协议:在 HDLC、PPP(点对点协议)、CAN 总线 等数据链路层协议中,使用 CRC-16 或 CRC-32 进行数据帧的完整性校验。CAN 总线(用于汽车、工业自动化)使用 CRC-15开展校验,USB 协议 采用 CRC-5 和 CRC-16进行数据包的错误检测。
1.2 存储设备
- 硬盘、SSD、RAID 纠错:在 机械硬盘 (HDD) 和 固态硬盘 (SSD) 读取数据时,数据可能因 磁场干扰、坏扇区 等原因而发生错误,因此使用 CRC 校验 来检测数据损坏。RAID(冗余阵列磁盘) 采用 CRC 结合 ECC(纠错码) 确保数据存储的可靠性。
- 光盘 (CD/DVD) 读取:CD、DVD、Blu-ray 盘片存储的数据容易受划痕、老化、光学误差影响,因此采用 CRC 进行错误检测,并结合 Reed-Solomon 纠错码 修复错误。
1.3 工业控制与嵌入式系统
- 物联网(IoT)、嵌入式设备:物联网 (IoT) 设备,如 智能传感器、无线模块、智能家居设备,使用 CRC 校验数据完整性,避免错误数据导致系统失效。
- 汽车电子(车载网络 CAN 总线):现代汽车的 ECU(电子控制单元)、传感器、自动驾驶系统 都依赖 CAN 总线 进行通信。CAN 总线使用 CRC-15 进行数据帧校验,防止错误命令导致汽车故障。
1.4 软件与文件完整性
- 数据文件传输校验:在文件下载或传输过程中,使用 CRC 校验文件的完整性,防止文件损坏或篡改。
- 数字签名 & 数据防篡改:CRC 可用于检测数据篡改,确保文件或数据包在存储或传输过程中未被恶意修改。区块链技术(Bitcoin、Ethereum)在交易数据中使用 哈希 + CRC 机制 检查数据完整性。银行 ATM 交易 采用 CRC-16 或 CRC-32 进行 PIN 码数据完整性校验。
- 软件校验:某些软件使用 CRC 校验自身代码是否被恶意修改。游戏反作弊系统 通过 CRC 检测游戏文件是否被修改,如 VAC(Valve 反作弊系统)。Windows PE 文件校验 通过 CRC-32 计算 PE 头部,防止病毒篡改系统文件。
1.5 科学计算 & 深空探测
- NASA 深空探测:在深空探测任务(如 火星探测器、哈勃望远镜)中,由于数据传输距离极远,CRC 与 Forward Error Correction (FEC) 结合,确保数据可靠传输。
小结
二、CRC校验原理
2.1 CRC 的校验本质
数据被视为一个二进制数,选择一个固定的 CRC 生成多项式(比如 x^4 + x + 1),然后使用二进制除法(不进位) 计算出余数(即 CRC 校验码)。将余数附加到数据后面,接收方可以通过相同的计算过程来检查数据是否正确。
2.2 CRC 校验的核心步骤
(1)选择 CRC 生成多项式
下图是常用的CRC模型,参照红框。通信双方可以约定一个相同的多项式。
其中:
- width是CRC码的位宽;
- poly是省略最高位的多项式,因为更利于编程实现,即移位之后不需要考虑最高位;
- init是CRC码初始值,因为原始数据可能以不同位数的0开头,所以需要设置初始值来区分;
- refin是输入逆向标志位,这里为真,表示输入数据需要先进行逆向(即按位倒序),再进行后续运算;
- refout是输出逆向标志位,这里为真,表示CRC码需要先进行逆向(即按位倒序),再输出;
- xorout是输出异或值,是输出CRC码前与其进行异或运算的数;
(2)发送端计算 CRC 码
- 将数据看作一个二进制数,假设发送 1011001(7 位)。
- 在数据后面添加 4 个 0(因为使用 CRC-4),变成 10110010000(11 位)。
- 用二进制除法(不进位) 计算 余数: 用 10110010000 除以 0011,得到余数(例如 0110)。
- 将余数 0110 附加到数据末尾,得到 10110010110。
(3)接收端校验
接收端收到 10110010110,用相同的 二进制除法 计算 CRC 余数:
- 如果余数为 0000,表示数据未出错 。
- 如果余**数 不为 **0000,表示数据出错 。
2.3 CRC 二进制除法示例
三、CRC校验代码实现步骤
注意实际编程时并不直接使用上述方法,以下是编程实现步骤:
1.选择合适的多项式
- CRC 校验的第一步是选择一个“生成多项式”。这个多项式决定了 CRC 计算的规则,不同的应用可能会选择不同的多项式。例如,CRC-16、CRC-32 分别使用不同的多项式。
- 多项式通常以标准形式给出,如 CRC-16-CCITT 使用的是 0x1021。
2. 初始化 CRC 寄存器
- CRC 计算开始前,CRC 寄存器(通常是一个与多项式位宽相同的寄存器)被初始化,常见的初始化值有全0或全1。
3. 预处理数据
- 根据具体的 CRC 类型,可能需要对数据进行预处理,如反转数据位(反射)。
4. 逐位计算 CRC
- 数据的每一位被逐一处理。每处理一个数据位,CRC 寄存器左移一位(模拟除法中的移位),并根据数据位决定是否执行 多项式异或。
- 如果 CRC 最高位为 1,则与多项式进行异或运算。
5. 后处理 CRC
- 根据特定的 CRC 标准,可能需要对最终的 CRC 寄存器进行后处理,例如可能需要再次进行位反射。
- 最终的 CRC 值可能还会与一个最终的异或值进行异或,以得到最终的 CRC 校验码。
note:此步骤是否执行需要参照下图红框
6. 输出 CRC 校验码
- 确保 CRC 结果为所需的位数(例如 CRC-4 需要 4 位),将最终的 CRC 校验码作为结果返回。
四、CRC校验代码(以CRC-4为例)
1 |
|
以下是运行结果示例:
五、总结
1.系统性的了解了CRC校验的用途、原理、编程实现,深刻理解了CRC校验的本质。
2.对于c++学习:
(1)学习了两个头文件iomanip 、stdexcept 。其中:
- 设置十六进制输出格式(hex)
- 大写字母格式(uppercase)
- 设置输出宽度和填充字符(setw()、setfill())
- std::invalid_argument (无效参数异常)
- std::out_of_range (超出范围异常)
- std::runtime_error (运行时错误异常)
这些异常可以用 throw 抛出,也可以用** **try-catch 语句捕获,防止程序崩溃。
(2)数据类型:uint8_t
使用 uint8_t(无符号 8 位整数)来定义 CRC_POLYNOMIAL(CRC 多项式)的原因是为了确保在内存中占用最小的空间,并且它的范围适合存储 CRC 多项式值。
(3)反转函数中的位运算符
reflected:作为存储反转后的数据//data & (1 << i): 用于检查 data 的第i位是否为1 这里”1”二进制数为0000 0001/reflected |= (1 << (7 - i)):这里一定要用 “|=” (按位或赋值运算符),若使用”=”,下次循环新的reflected会覆盖上一轮的结果。
(4)^= 表示异或运算
(5)static_cast
- 显式转换不同类型的数据(如 int → uint8_t)。
- 确保转换是安全的(编译时进行检查)。
- 不会影响底层数据的存储方式。
为什么不直接使用 uint8_t data = tempData;?
tempData 是 int 类型(32 位),直接赋值给 uint8_t(8 位)时,可能产生溢出。