C/C++实现CRC码计算和校验
简介
CRC(Cyclic Redundancy Check)循环冗余校验码是一种通过计算来检测数据传输错误的方法,它通过对数据进行简单的计算得到一个固定长度的校验码,根据接收方收到的数据计算出的校验码和发送方计算出来的校验码进行比较来判断数据传输是否正确。
本文将介绍如何实现C/C++版的CRC码计算和校验,同时提供两个示例来说明如何使用。
CRC算法
对于一个要传输的数据d,CRC算法会计算出一个固定大小的校验码C,加上数据d和校验码C之后拼接成新的数据D,发送。接收方收到数据D之后,会计算接收到的数据的校验码C',如果C'与发送方计算出的校验码C一致,就说明数据传输正确无误。
通常我们使用的CRC算法都是基于多项式的下面这个公式计算得到的:
CRC(x) = r(x) mod g(x)
其中,x表示位,r(x)是要计算的数据,g(x)是一个系数多项式,mod是一个取模运算。
对于一个数据r(x)和一个G(x)多项式,执行CRC计算的过程如下:
- 将r(x)的高位填充G(x)的系数位数个0,得到p(x)
- 对p(x)和G(x)进行异或操作,得到余数d(x),把d(x)存储到p(x)的最高位
- 把p(x)的高位弹出,转到第二步,直到所有r(x)的位数处理完毕
最终得到的p(x)就是计算出的CRC码。接收方收到数据之后也用同样的算法计算出接收到的数据的CRC码,如果接收方计算出的CRC码与发送方计算出的CRC码相同,则说明数据传输正确。
C/C++实现
在C/C++中,我们可以通过计算得到一个数据的CRC码,也可以在接收到数据后计算数据的CRC码并校验。
CRC码计算
在C/C++中,计算CRC码的过程可以用一个函数来实现。我们可以定义一个函数,它接收一个指向数据的指针和数据的长度,同时再定义一个G(x)系数多项式,函数会返回计算出的CRC码。
一个常用的CRC16算法如下:
uint16_t CRC16(uint8_t *pdata, uint32_t len, uint16_t polynominal) {
uint16_t crc = 0xFFFF;
uint8_t i;
while (len--) {
crc ^= *pdata++;
for (i = 0; i < 8; i++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= polynominal;
}
else {
crc >>= 1;
}
}
}
return crc;
}
该函数接收三个参数,pdata表示数据的指针,len表示数据长度,polynominal表示多项式系数。函数首先初始化一个crc变量为0xFFFF,然后对于每一个数据位执行一次循环,对于每一位,执行一次异或运算,然后进行8次迭代,每一次迭代都判断是否需要执行异或操作,最终得到的crc值就是计算出的CRC码。
CRC码校验
在C/C++中,校验CRC码的过程也可以用一个函数来实现。与计算CRC码的过程类似,校验CRC码的函数需要接收一个指向数据的指针和数据的长度以及一个该数据对应的CRC码。
一个常用的CRC16校验函数如下:
bool CheckCRC16(uint8_t *pdata, uint32_t len, uint16_t crc, uint16_t polynominal) {
uint16_t crc_calculated = CRC16(pdata, len, polynominal);
return crc == crc_calculated;
}
该函数接收四个参数,pdata表示数据的指针,len表示数据长度,crc表示接收到的CRC码,polynominal表示多项式系数。函数首先调用计算CRC码的函数计算出接收到的数据的CRC码,然后判断计算出的CRC码是否与接收到的CRC码相等,如果相等则返回true,否则返回false。
示例
下面我们提供两个示例来说明怎样使用C/C++来实现CRC码计算和校验。
示例一:计算字符串CRC码
#include <stdio.h>
#include <stdint.h>
/*CRC16多项式*/
const uint16_t POLYNOMIAL = 0xA001;
/*计算CRC16*/
uint16_t CRC16(uint8_t *pdata, uint32_t len, uint16_t polynominal) {
uint16_t crc = 0xFFFF;
uint8_t i;
while (len--) {
crc ^= *pdata++;
for (i = 0; i < 8; i++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= polynominal;
}
else {
crc >>= 1;
}
}
}
return crc;
}
int main() {
uint8_t data[] = {"Hello World!"};
uint32_t len = sizeof(data);
uint16_t crc_calculated = CRC16(data, len - 1, POLYNOMIAL);
printf("CRC16: %04X\n", crc_calculated);
return 0;
}
该示例演示了如何计算字符串的CRC16码。在主函数中,我们定义了一个字符串变量data,该字符串包含13个字符,分别为“Hello World!”,我们将该字符串作为数据,调用CRC16函数计算它的CRC16码,最终输出计算出的CRC16码。
示例二:校验接收到的数据
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
/*CRC16多项式*/
const uint16_t POLYNOMIAL = 0xA001;
bool CheckCRC16(uint8_t *pdata, uint32_t len, uint16_t crc, uint16_t polynominal) {
uint16_t crc_calculated = CRC16(pdata, len, polynominal);
return crc == crc_calculated;
}
int main() {
uint8_t data[] = {"Hello World!"};
uint32_t len = sizeof(data);
/*模拟接收到的数据(包含CRC码)*/
uint8_t received_data[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x94, 0x62 };
/*从数据中提取CRC码*/
uint16_t crc = received_data[len - 2] << 8 | received_data[len - 1];
/*校验CRC码*/
bool result = CheckCRC16(data, len - 1, crc, POLYNOMIAL);
if (result) {
printf("CRC Check passed.\n");
}
else {
printf("CRC Check failed.\n");
}
return 0;
}
该示例演示了如何校验接收到的数据的CRC码。在主函数中,我们定义了一个字符串变量data,该字符串包含13个字符,分别为“Hello World!”,我们将该字符串作为数据,然后模拟接收到了一组数据,其中包含了我们发送的数据以及计算出的CRC码。我们从接收到的数据中提取出CRC码,然后调用CheckCRC16函数校验接收到的数据的CRC码是否正确,最终输出校验结果。
结论
本文介绍了如何在C/C++中实现CRC码计算和校验,通过两个示例演示了如何计算字符串的CRC码以及如何校验接收到的数据的CRC码。希望能帮助到需要进行CRC码计算和校验的读者。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C/C++实现crc码计算和校验 - Python技术站