常用的简单校验算法:校验和,异或校验,crc校验,LRC校验,补码求和,checksum
相关思路和源码来自网络,自己只是整理, 做笔记用。
并未完整完善正确归纳,只是个人理解初步做笔记记录。
在实现业务需求过程中,通常要用到相关一些校验算法,简单整理常用校验算法并做笔记:
常用校验算法简单说明:
1:校验和:按每个字节,计算累加和,
2:异或校验:定义初值,按每个字节异或,求结果。
3:CRC校验:已有很多的标准及计算方式,可以返回8字节,16字节,32字节的结果。
设置crc值和多项式码;依次遍历每个字节,与crc值进行异或;crc值取出最低位的值,并右移一位;如果最低位值位1,则于多项式码进行异或;循环直到8位结束。
crc查表思想:观察,内部有个循环,每次对一个字节(8位)的循环中,对crc码的数字是不变的,这里与多项式码相关,可以直接用数组代替这里的求值。(crc表与crc返回8/16/32位有关,与多项式码有关)
4:LRC校验:是不可靠的,先求和,再对结果取反+1
5:checksum:对checksum值归0,每16bit求和,不够16bit的高位补0,如果checksum溢出,则高16bit和低16bit相加进行处理(依次循环判断)。
测试demo:
//实现对原数据进行checksum计算校验测试demo #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> //校验和 返回一个字节 unsigned char Check(const unsigned char *buf, int len) { int iSum = 0; for (int i = 0;i < len;i++) { iSum += buf[i]; } iSum %= 0x100; //也可以&0xff return (unsigned char)iSum; } //异或校验 返回一个字节 unsigned char CheckXor(const char *strData,int len) { char checksum = 0; for (int i = 0;i < len;i++) { checksum = checksum ^ strData[i]; } return (unsigned char)checksum; } //电子通信领域非常常用,已经有一些特定的计算方式 //CRC校验 (返回两个字节 高字节在前,低字节在后) 循环冗余校验 unsigned short int CRC(const unsigned char *buf, int leng) { unsigned short int Reg,temp,Crccode,i,j; Reg = 0xFFFF; //设置crc的值 FF FF Crccode = 0xA001; //定义的一个多项式码,最终都会与这个码异或 for ( i=0;i<leng;i++ ) { Reg ^= *(buf+i); //进行异或 与crc的低8位 // ==》注意这里的循环 其实都是固定的值,可以直接计算生成一个表来直接获取 for ( j=0;j<8;j++ ) { temp=Reg&0x0001; //获取当前最低位的数字 Reg=Reg>>1; //向右移一位 if( temp==0x0001 ) //判断移出的最低位的值,如果为1,则与上文定义的多项式码进行异或,为0,则不处理 Reg^=Crccode; } } //重复处理完所有的数据 return (Reg<<8 | Reg>>8); //(Reg^ 0xffff) ==>这里其实做了反转 } // 纵向冗余校验 异或校验和 不可靠 //LRC校验 求和 取反 +1 unsigned char LRC(const unsigned char *auchMsg, unsigned short usDataLen) { unsigned char uchLRC=0; while(usDataLen--) { uchLRC+=*auchMsg++; } return ((unsigned char)(-((char)uchLRC))); } //补码求和 unsigned char Check1(const unsigned char *buf, int len) { int iSum = 0; for (int i = 0;i < len;i++) { iSum += buf[i]; } iSum = 256 - iSum; return (unsigned char)iSum; } //把传入checksum置为0 每2个字节求和 //这里没有加入溢出情况 将高16bit和低16bit相加处理 uint32_t checksum(const void *buf, size_t len, uint32_t sum) { /* workaround gcc strict-aliasing warning */ uintptr_t ptr = (uintptr_t)buf; typedef uint16_t __attribute__((__may_alias__)) u16_p; const u16_p *u16_buf = (const u16_p *)ptr; //把数据按照2byte进行划分 //减少循环次数而已 while (len >= (sizeof(*u16_buf) * 4)) { //把2byte对应的值,依次累加到一个4byte值中 sum += u16_buf[0]; sum += u16_buf[1]; sum += u16_buf[2]; sum += u16_buf[3]; len -= sizeof(*u16_buf) * 4; u16_buf += 4; } while (len >= sizeof(*u16_buf)) { //把不够4位的,也加入sum中 sum += *u16_buf; len -= sizeof(*u16_buf); u16_buf += 1; } /* if length is in odd bytes */ if (len == 1) //如果最后的数据不够2byte,其实就是当成2byte处理,高位补0 sum += *((const uint8_t *)u16_buf); return sum; //这里对最终的结果是如何处理的? 参考具体代码或者业务 } int main(int argc, char* argv[]) { //校验和测试 返回一个字节 const char * src_data = "abcdefghi"; printf("check %02x \n", Check((const unsigned char*)src_data, strlen(src_data))); //check 8d printf("CheckXor %02x \n", CheckXor((const char*)src_data, strlen(src_data))); //CheckXor 61 printf("CRC : %02x \n", CRC((const unsigned char*)src_data, strlen(src_data))); //CRC : 7f00 printf("LRC: : %02x \n", LRC((const unsigned char*)src_data, strlen(src_data))); //LRC: : 73 printf("Check1: %02x \n", Check1((const unsigned char*)src_data, strlen(src_data))); //Check1: 73 printf("sizeof(char*) = %lu \n", sizeof(char*)); unsigned int cksum = checksum((const void*)src_data, strlen(src_data), 0); //checksum : 6a06 cksum = (cksum == 0xffff) ? cksum : (uint16_t)~cksum; printf("checksum : %02x \n", cksum); //使用简单的异或的方案,进行简单的测试 const char* data = "2|4|12312|119|{\"InternalFleetNum\":\"12345\",\"CoordX\":1178263,\"CoordY\":2083177,\"Heading\":121.7,\"LocationCode\":\"AVB\",\"RequestId\":1234567}"; printf("data is [%s] \n",data); char* buff = NULL; buff = (char*)malloc(strlen(data) +2); memset(buff, 0, strlen(data) +2); memcpy(buff, data, strlen(data)); printf("buff is [%s] \n",buff); unsigned char check_xor = CheckXor((const char*)data, strlen(data)); printf("check_xor = [%c] \n", check_xor); memcpy(buff+strlen(data), (char*)&check_xor, 1); printf("buff adn check_xor is [%s] \n",buff); //试一下校验 收到的是buff 然后数据的总长度是 strlen(data)+1 unsigned char check_xor1 = CheckXor(buff, strlen(buff)-1); printf("check_xor1 is [%c] \n", check_xor1); // if(check_xor != (unsigned char)recv_buff+len-1) printf("data check_xor is [%c] \n", *(buff+strlen(buff)-1)); if(check_xor1 == *(buff+strlen(buff)-1)) { printf("data is success ! \n"); }else { printf("data is error! \n"); } return 0; } /*************************** check 8d CheckXor 61 CRC : 7f00 LRC: : 73 Check1: 73 sizeof(char*) = 8 checksum : 6a06 data is [2|4|12312|119|{"InternalFleetNum":"12345","CoordX":1178263,"CoordY":2083177,"Heading":121.7,"LocationCode":"AVB","RequestId":1234567}] buff is [2|4|12312|119|{"InternalFleetNum":"12345","CoordX":1178263,"CoordY":2083177,"Heading":121.7,"LocationCode":"AVB","RequestId":1234567}] check_xor = [S] buff adn check_xor is [2|4|12312|119|{"InternalFleetNum":"12345","CoordX":1178263,"CoordY":2083177,"Heading":121.7,"LocationCode":"AVB","RequestId":1234567}S] check_xor1 is [S] data check_xor is [S] data is success ! ****************************/