参考:
Vector - CAPL - CRC算法介绍
开发工具 > CRC校验工具
文章目录
- 简介
- CRC-8
- CRC-16
- CRC-32
简介
循环冗余校验(Cyclic Redundancy Check,简称CRC)是一种数据校验算法,广泛用于检测数据传输或存储过程中的错误。它通过计算数据的校验和来检测数据是否在传输过程中发生了错误。以下是几种常用的CRC校验算法:
CRC-8
- 多项式:常用的多项式有
0x07
(x^8 + x^2 + x + 1)、0x31
(x^8 + x^5 + x^4 + 1)等。 - 应用:常用于简单的数据校验,如一些简单的通信协议中。
CRC-16
- 多项式:常用的多项式有
0x8005
(x^16 + x^15 + x^2 + 1)、0xA001
(x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^5 + x^2 + 1)等。 - 应用:广泛用于各种通信协议和文件格式中,如Modbus协议、MPEG-2等。
CRC-32
- 多项式:最常用的是
0x04C11DB7
(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)。 - 应用:广泛应用于网络协议(如以太网)、文件压缩(如ZIP文件)、文件系统(如FAT32)等。
CRC-64
- 多项式:常用的多项式有
0x42F0E1EBA9EA3693
(ECMA-182标准)等。 - 应用:用于需要更高校验精度的场合,如大型文件的完整性校验。
CRC算法特点
- 简单高效:CRC算法相对简单,计算速度快,适合实时数据传输校验。
- 检测能力:能有效检测突发错误(burst errors),即连续的错误比特。
- 可配置性:通过选择不同的多项式,可以适应不同的应用场景和错误检测需求。
CRC算法实现
CRC算法通常通过位操作实现,包括位移、异或等操作。对于不同的多项式和数据长度,可以预先计算出一个查找表(lookup table),以提高计算效率。例如,CRC-32算法在许多编程语言中都有现成的库函数可供使用。
CRC算法虽然能有效检测数据错误,但不能纠正错误,因此在需要纠错的场合,还需要结合其他纠错编码技术。
在CRC校验中常见的主要有CalculateCRC8、CalculateCRC8H2F、CalculateCRC16、CalculateCRC32、CalculateCRC32P4、CalculateCRC64。
CRC-8
宽度:8位 多项式:0x07 初始值:0x00 异或值:00
#include <iostream>
#include <vector>
#include <cstdint>template <typename Container>
static uint8_t calculateCRC8(const Container& data, int len)
{uint8_t InitCrc = 0x07;uint8_t crc = 0;int i, j;for (i = 0; i < len; i++) {crc ^= data[i];for (j = 0; j < 8; j++) {if (crc & 0x80) {crc = (crc << 1) ^ InitCrc;}else {crc <<= 1;}}}return crc;
}int main()
{// 创建一个样本数据std::vector<uint8_t> data = { 0x01, 0x02, 0x03, 0x04, 0x05 };// 计算整个数据的 CRC8uint8_t crc = calculateCRC8(data,data.size());// 输出结果std::cout << "CRC8: 0x" << std::hex << static_cast<int>(crc) << std::endl;// 检查结果是否符合预期// 假设我们预期的 CRC8 值是 0x9Buint8_t expected_crc = 0xBC;if (crc == expected_crc) {std::cout << "CRC8 calculation is correct." << std::endl;}else {std::cout << "CRC8 calculation is incorrect." << std::endl;}
}
CRC-16
宽度:16位 多项式:0x07 初始值:0x00 异或值:00
#include <iostream>
#include <vector>
#include <cstdint>// 反转一个8位的值
uint8_t reverseBits(uint8_t value) {uint8_t result = 0;for (int i = 0; i < 8; i++) {result = (result << 1) | (value & 1);value >>= 1;}return result;
}template <typename Container>
static uint16_t calculateCRC16(const Container& data, int len) {// CRC-16多项式,x^16 + x^15 + x^2 + 1uint16_t polynomial = 0x8005;// CRC-16初始值uint16_t crc = 0x0000;int i, j;for (i = 0; i < len; i++) {// 反转数据字节uint8_t reversedData = reverseBits(data[i]);crc ^= static_cast<uint16_t>(reversedData) << 8;for (j = 0; j < 8; j++) {if (crc & 0x8000) {crc = (crc << 1) ^ polynomial;}else {crc <<= 1;}}}// 反转最终的CRC值crc = (crc >> 8) | (crc << 8);crc = reverseBits(static_cast<uint8_t>(crc & 0xFF)) | (reverseBits(static_cast<uint8_t>(crc >> 8)) << 8);return crc;
}int main() {// 创建一个样本数据std::vector<uint8_t> data = { 0x01, 0x02, 0x03, 0x04, 0x05 };// 计算整个数据的CRC-16uint16_t crc = calculateCRC16(data, data.size());// 输出结果std::cout << "CRC-16: 0x" << std::hex << crc << std::endl;// 检查结果是否符合预期// 假设我们预期的CRC-16值是0xXXXXuint16_t expected_crc = 0xbb0e; // 请根据实际情况替换为预期值if (crc == expected_crc) {std::cout << "CRC-16 calculation is correct." << std::endl;}else {std::cout << "CRC-16 calculation is incorrect." << std::endl;}
}
CRC-32
改了半天终于对了,可能和大小端有关系
从您的描述和计算结果来看,问题可能出在几个方面:
- 反向字节的顺序:在计算 CRC32 时,通常字节顺序和位顺序是反转的。即字节顺序按反向处理,而每个字节内的位也需要反转。
- 正确的 CRC32 算法实现:我们应该确保按标准的 CRC32 算法来进行处理。最常见的 CRC32 是基于 ISO 802.3
标准,它的计算方法会要求从一个初始化值开始,对每个字节进行计算并使用最终的异或值。 - 字节处理顺序和位反转:需要确保数据和多项式都正确地按照字节顺序(小端序或大端序)来处理。
#include <iostream>
#include <vector>
#include <cstdint>
#include <iomanip> // 用于格式化输出const uint32_t CRC32_POLY = 0xEDB88320; // 反向多项式
const uint32_t CRC32_INIT = 0xFFFFFFFF; // CRC-32初始值
const uint32_t CRC32_XOR_OUT = 0xFFFFFFFF; // CRC-32最终异或值// CRC32查找表
uint32_t crc32Table[256];// 初始化CRC32查找表
void initCRC32Table() {for (uint32_t i = 0; i < 256; ++i) {uint32_t crc = i;for (uint32_t j = 8; j > 0; --j) {if (crc & 1) {crc = (crc >> 1) ^ CRC32_POLY;}else {crc >>= 1;}}crc32Table[i] = crc;}
}// 计算CRC32
uint32_t calculateCRC32(const std::vector<uint8_t>& data) {uint32_t crc = CRC32_INIT;for (size_t i = 0; i < data.size(); ++i) {uint8_t byte = data[i];crc = (crc >> 8) ^ crc32Table[(crc ^ byte) & 0xFF];}crc ^= CRC32_XOR_OUT;return crc;
}int main() {// 初始化CRC32查找表initCRC32Table();// 待校验的数据std::vector<uint8_t> data = { 0x01, 0x02, 0x03, 0x04, 0x05 , 0x06 };// 计算CRC-32校验值uint32_t crc = calculateCRC32(data);// 输出CRC-32校验值std::cout << "CRC-32: 0x" << std::hex << std::uppercase << std::setw(8) << std::setfill('0') << crc << std::endl;// 检查结果是否符合预期uint32_t expected_crc = 0x81F67724; // 预期的CRC-32值if (crc == expected_crc) {std::cout << "CRC-32 calculation is correct." << std::endl;}else {std::cout << "CRC-32 calculation is incorrect." << std::endl;}return 0;
}