crc怎么算
在计算机领域中,CRC(循环冗余校验)是一种常用的错误检查码。它可以通过对数据帧中的数据进行计算和附加校验值来检查通信过程中的错误。在接下来的文章中,我们将从下面三个角度分析CRC,它的基本原理,常用的CRC算法以及如何实现CRC校验。
一、CRC的基本原理
CRC通过在数据块的末尾添加一个错误检查码来保证数据块的完整性。这个检查码是通过对数据块中所有位进行计算而得到的。CRC计算的基本原理是将n+1位的除数,对应于一个n位数据块和m位的余数是0。例如,一个16位数据块的除数可能是0x1021,即17位(16位数据块+一个位为0的高阶位),这个除数对应于一个15位的余数,使得任何15位的编号都可以被此除数除尽。检验过程是将余数附加到数据块的末尾,发送数据块,则接收方可以执行相同的计算,计算出余数,并比较收到的CRC码是否与原始的CRC码相符。
二、常用的CRC算法
常用的CRC算法有很多种,其中最常见的是CRC-32算法。CRC-32是一个32位的CRC算法,常用于磁盘和网络传输。CRC-32算法将数据块当做一个32位的二进制数,并使用一个固定的循环码多项式,对数据块进行异或。CRC-32多项式是0x04C11DB7,是一个3字节多项式,虽然它包含了32位,但至少需要4字节的空间来存储检验数据。
另外,还有CRC-8和CRC-16算法。CRC-8主要用于蓝牙协议和I2C数据总线,它是一个8位的CRC算法,使用的多项式是0x07。CRC-16是一个16位的CRC算法,常用于Modbus和CAN总线,多项式是0x8005。
三、如何实现CRC校验
现在大部分的通信设备都支持CRC校验,具体实现因平台和语言而异,但他们的过程基本相同。以下是一个C++实现CRC-32校验的例子。
```C++
uint32_t crc32(const void* data, size_t len) {
static uint32_t crc_table[256];
static bool table_set = false;
uint8_t* p = (uint8_t*)data;
uint32_t crc = 0xFFFFFFFF;
if (!table_set) {
for (int i = 0; i < 256; i++) {
uint32_t c = i;
for (int j = 0; j < 8; j++) {
if (c & 1) {
c = 0xEDB88320L ^ (c >> 1);
} else {
c >>= 1;
}
}
crc_table[i] = c;
}
table_set = true;
}
while (len--) {
crc = crc_table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
}
return crc ^ 0xFFFFFFFF;
}
```
这个例子使用了一个32位的数据类型,通过一个静态变量数组crc_table,存储了一张快速查找表。这个表被用来计算CRC码。