[C/C++]常用数据校验方法:CRC校验

本文介绍了CRC校验的原理,包括其优点、CRC多项式的不同版本(如CRC-8和CRC-32),以及在嵌入式通信中的应用,如在数据包结构中的使用和CRC32校验码的生成过程。
摘要由CSDN通过智能技术生成

CRC是什么?

CRC校验计算速度快,检错能力强,一些芯片支持编码器等硬件电路实现。从检错的正确率与速度、成本等方面,都比奇偶校验等校验方式具有优势。因而,CRC 成为计算机信息通信领域最为普遍的校验方式。

完整的crc模型应该具有一下特征:

  1. 参数模型Name
  2. 生成的数据宽带,如CRC-8,生成的crc校验码为8位,CRC-32生成的校验码为32位
  3. 多项式,比如x8+x2+x+1,二进制为100000111, 转换为十六进制省略最高位为0x07
  4. 初始值INIT,与数据宽带一样
  5. 原始数据是否反转REFIN,为true或者false
  6. 输出的crc值是否反转,大小位交换,比如 1010翻转后为0101
  7. 计算结果与此参数进行异或运算XOROUT,结果与位宽一致

得出一个数的CRC校验码还是比较简单的:

  1. 选定一个CRC生成多项式G(x);
  2. 将发送数据左移K位,右侧补零(其中K为生成多项式最高次幂);
  3. 用移位补零后的数据对G(x)进行模2除法(其实就是异或运算);
  4. 用得到的余数即为该数据的CRC校验码;

CRC校验数据整计算

在嵌入式通讯中,比如ota,modlbus,uart,在数据包里都会包含校验值,通常数据包的格式如下:

typedef struct {
	char type; //消息类型
	int len;  //数据长度
	unsigned char* data; //数据
	unsigned  int check;  //crc32校验值
}node_date_t;

如何对整个数据帧进行校验:
一个数据的校验结果要作为下一个数据校验过程中移位寄存器的初值,如此循环往复在数据帧的下一拍就能输出整个数据帧的校验值了

CRC32校验码生成

uint32_t CRC32(uint_8 *data, uint16_t len)
{
	//多项式 x32+x26+x23+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 
	//最高位省略,即100 1100 0001 0001 1101 1011 0111
	uint32_t poly = 0x4c11DB7  ;
	
	uint32_t init_value = 0xffffffff;
	uint_8 datai;
	while(len--){
		init_value ^= *data << 24 ;  //左移24位与初值进行异或
		//利用for循环,对每一位数据进行处理,如果是1,新值左移一位后与多项式进行异或,
		//如果是0,仅左移
		for(int i = 0; i < (sizeof(uint_8) * 8); i++){
			if(init_value & 0x8000000)
				init_value  =  (init_value << 1) ^ poly;
			else
				init_value <<= 1;
		}
		data++;
	}
	return init_value;
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++实现CRC8、CRC16、CRC32校验数据的示例代码: ```c++ #include <iostream> #include <cstring> using namespace std; // CRC8校验 uint8_t calc_crc8(uint8_t *data, uint32_t len) { uint8_t crc = 0x00; uint8_t gen_poly = 0x07; for (uint32_t i = 0; i < len; i++) { crc ^= data[i]; for (uint8_t j = 0; j < 8; j++) { if (crc & 0x80) crc = (crc << 1) ^ gen_poly; else crc <<= 1; } } return crc; } // CRC16校验 uint16_t calc_crc16(uint8_t *data, uint32_t len) { uint16_t crc = 0xFFFF; uint16_t gen_poly = 0x1021; for (uint32_t i = 0; i < len; i++) { crc ^= (uint16_t)data[i] << 8; for (uint8_t j = 0; j < 8; j++) { if (crc & 0x8000) crc = (crc << 1) ^ gen_poly; else crc <<= 1; } } return crc; } // CRC32校验 uint32_t calc_crc32(uint8_t *data, uint32_t len) { uint32_t crc = 0xFFFFFFFF; uint32_t gen_poly = 0xEDB88320; for (uint32_t i = 0; i < len; i++) { crc ^= data[i]; for (uint8_t j = 0; j < 8; j++) { if (crc & 0x00000001) crc = (crc >> 1) ^ gen_poly; else crc >>= 1; } } return ~crc; } int main() { // 测试数据 uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05}; uint32_t len = sizeof(data); // CRC8校验 uint8_t crc8 = calc_crc8(data, len); cout << "CRC8: 0x" << hex << (int)crc8 << endl; // CRC16校验 uint16_t crc16 = calc_crc16(data, len); cout << "CRC16: 0x" << hex << crc16 << endl; // CRC32校验 uint32_t crc32 = calc_crc32(data, len); cout << "CRC32: 0x" << hex << crc32 << endl; return 0; } ``` 注意,以上示例代码仅为演示CRC校验算法的实现,实际应用中可能需要对输入数据进行预处理(如填充、反转、异或等)以满足特定的校验需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值