草庐IT

常用的简单校验算法:校验和,异或校验,crc校验,LRC校验,补码求和,checksum

yun6853992 2023-04-09 原文

常用的简单校验算法:校验和,异或校验,crc校验,LRC校验,补码求和,checksum

相关思路和源码来自网络,自己只是整理, 做笔记用。

并未完整完善正确归纳,只是个人理解初步做笔记记录。

在实现业务需求过程中,通常要用到相关一些校验算法,简单整理常用校验算法并做笔记:

常用校验算法简单说明:

1:校验和:按每个字节,计算累加和,

2:异或校验:定义初值,按每个字节异或,求结果。

3:CRC校验:已有很多的标准及计算方式,可以返回8字节,16字节,32字节的结果。

受益匪浅的文章:https://blog.csdn.net/u013073067/article/details/86621770

​ 设置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 ! 
****************************/

有关常用的简单校验算法:校验和,异或校验,crc校验,LRC校验,补码求和,checksum的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - rbenv 安装 ruby​​ 校验和不匹配 osx - 2

    我已经在mountainlion上成功安装了rbenv和ruby​​build。运行rbenvinstall1.9.3-p392结束于:校验和不匹配:ruby-1.9.3-p392.tar.gz(文件已损坏)预期f689a7b61379f83cbbed3c7077d83859,得到1cfc2ff433dbe80f8ff1a9dba2fd5636它正在下载的文件看起来没问题,如果我使用curl手动下载文件,我会得到同样不正确的校验和。有没有人遇到过这个?他们是如何解决的? 最佳答案 tl:博士;使用浏览器从http://ftp.rub

  3. ruby - RVM pkg 安装校验和错误 - 2

    root@li417-132:~#rvmpkginstallzlibFetchingzlib-1.2.7.tar.gzto/usr/local/rvm/archivesThereisnochecksumfor'http://prdownloads.sourceforge.net/libpng/zlib-1.2.7.tar.gz'or'zlib-1.2.7.tar.gz',it'snotpossibletovalidateit.Ifyouwishtocontinuewithunverifieddownloadadd'--verify-downloads1'afterthecommand.

  4. ruby-on-rails - 在 Rails 3 中进行身份验证最常用的方法是什么? - 2

    我需要在rail3中使用标准注册/登录/忘记密码功能进行身份验证。是否有大多数人为此使用的插件或其他东西? 最佳答案 我不确定最常用的方法是什么-但可以肯定的是,Plataformatec的“Devise”是一个非常流行的方法:http://github.com/plataformatec/devise我已经尝试了一些authgem,对我来说,它是最简单的设置和修改以满足我的需要。它内置了密码恢复、帐户确认(如果需要)和其他一些非常方便的功能。 关于ruby-on-rails-在Rail

  5. ruby-on-rails - 如何在 Rails 中添加禁用的提交按钮 - 2

    我在ruby​​表单中有一个提交按钮f.submitbtn_text,class:"btnbtn-onemgt12mgb12",id:"btn_id"我想在不使用任何javascript的情况下通过ruby​​禁用此按钮 最佳答案 添加disabled:true选项。f.submitbtn_text,class:"btnbtn-onemgt12mgb12",id:"btn_id",disabled:true 关于ruby-on-rails-如何在Rails中添加禁用的提交按钮,我们在St

  6. ruby - 如何保持我不常用的编程语言技能 - 2

    关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby​​-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby​​有很大不同。由于我与ruby​​之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?

  7. 电脑怎么截图?进来看(8种常用截图方法) - 2

    电脑上可以截取图片吗?如果可以,该如何操作呢?相信很多小伙伴都只知道一两种截图的方式,知道的并不全面。其实,电脑上有多种方式截图的,而且非常方便。电脑怎么截图?今天我们就来教大家如何使用电脑截取图片的8种常用方式!操作环境:演示机型:Delloptiplex7050系统版本:Windows10方法一:系统自带截图具体操作:同时按下电脑的自带截图键【Windows+shift+S】,可以选择其中一种方式来截取图片:截屏有矩形截屏、任意形状截屏、窗口截屏和全屏截图。 方法二:QQ截图具体操作:在电脑登录QQ,然后同时按下【Ctrl+Alt+A】,可以任意截图你需要的界面,可以把截图的页面直接下载,

  8. ruby - 为什么 Ruby 注入(inject)方法不能对没有初始值的字符串长度求和? - 2

    为什么下面的代码会报错?['hello','stack','overflow'].inject{|memo,s|memo+s.length}TypeError:can'tconvertFixnumintoStringfrom(irb):2:in`+'from(irb):2:in`blockinirb_binding'from(irb):2:in`each'from(irb):2:in`inject'from(irb):2如果传递了初始值,它就可以正常工作:['hello','stack','overflow'].inject(0){|memo,s|memo+s.length}=>18

  9. ruby - 求和 ruby​​ 哈希值 - 2

    我正在尝试从ruby​​散列中求和值,但使用inject或reduce都没有返回正确答案。似乎这些方法正在覆盖存储的当前值而不是对它们求和。我的哈希看起来像这样:@test=[{"total"=>18,"type"=>"buy","date"=>Thu,21Nov2013,"instrument_code"=>"food"},{"total"=>92,"type"=>"buy","date"=>Thu,14Nov2013,"instrument_code"=>"food"},{"total"=>12,"type"=>"buy","date"=>Wed,20Nov2013,"instru

  10. ruby serialport gem,谁负责检查奇偶校验错误? - 2

    gem串口(1.0.4)作者:GuillaumePierronnet、AlanStern、DanielE.Shipton、Tobin理查德、赫克托·帕拉、瑞安·C·佩恩首页:http://github.com/hparra/ruby-serialport/使用RS-232串行端口的库。我正在使用这个gem,我的设备规范如下。9600bps7位1个停止位偶数当我收到如下数据时,解压后的数据仍然带有奇偶校验位。sp=SerialPort.new("/dev/serial-device",9600,7,1,SerialPort::EVEN)data=sp.getsdata.chars.eac

随机推荐