C语言标准CRC-32校验函数

news2024/11/29 1:30:50

C语言标准CRC-32校验函数

CRC-32校验产生4个字节长度的数据校验码,通过计算得到的校验码和获得的校验码比较,用于验证获得的数据的正确性。获得的校验码是随数据绑定获得。

CRC校验原理及标准CRC-8校验函数可参考:C语言标准CRC-8校验函数。这里介绍CRC-32的64位计算方式和简化的32位计算方式。

设计原理

设计原理仍然基于无符号64位整型为一个计算单元,当超过64位时,将前一个单元的计算余数,与后面的输入数据重新组成64位数据,再进行模二除法,以此类推,得到最后的CRC-32校验值(余数)。设计按照CRC计算基本原理来实现,以契合理解对照。

CRC-32校验函数

这里的校验码采用标准校验码x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1,对于其它类型的CRC-32校验码或有输入数据前处理或输出数据后处理的情况,相应的做代码简单调整即可。CRC-32校验函数如下:

#include <stdio.h>
#include <stdlib.h>
uint32_t PY_CRC_32(uint8_t *di, uint32_t len)
{
    uint64_t crc_poly = 0x104C11DB7;  //X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+1 total 33 effective bits. Computed total data shall be compensated 32-bit '0' before CRC computing.

	uint8_t *datain;
	uint64_t cdata = 0; //Computed total data
    uint64_t data_t = 0; //Process data of CRC computing

	uint16_t index_t = 63;  ///bit shifting index for initial '1' searching
	uint16_t index = 63;    //bit shifting index for CRC computing
	uint8_t rec = 0; //bit number needed to be compensated for next CRC computing


    uint32_t cn=(len+4)/4;
    uint32_t cr=(len+4)%4;

	uint32_t j;

	datain = malloc(len+4);
	for(j=0;j<len;j++)
	{
		datain[j]=di[j];
	}
        datain[len]=0; datain[len+1]=0; datain[len+2]=0; datain[len+3]=0;//Compensate 32-bit '0' for input data

    if(len<=4)   //Mount data for only one segment
     {
    	 for(j=0;j<=(len+3);j++)
    	 {
    		 cdata = (cdata<<8);
    		 cdata = cdata|datain[j];
    	 }
    	 cn = 1;
     }
    else
     {
    	 if(cr==0)
    	 {
    		 cr = 8;
             cn--;
    	 }
         else if(cr==1)
         {
             cr = 5;
         }
         else if(cr==2)
         {
             cr = 6;
         }
         else if(cr==3)
         {
             cr = 7;
         }
         else;

    	 for(j=0;j<cr;j++)
    	 {
    		 cdata = (cdata<<8);
    		 cdata = cdata|datain[j];
    	 }
     }

     do
     {
 		cn--;

 		while(index_t>0)
 		{
 			if( (cdata>>index_t)&1 )
 			{
 				index = index_t;
 				index_t = 0;

 				data_t |= (cdata>>(index-32));
 				{
 					data_t = data_t ^ crc_poly;
 				}

 	            while((index!=0x5555)&&(index!=0xaaaa))
 	            {

	 	    		for(uint8_t n=1;n<33;n++)
	 	    		{
	 	    			if ((data_t>>(32-n))&1) {rec = n;break;}
	 	    			if (n==32) rec=33;
	 	    		}

 	    			if((index-32)<rec)
 	    			{
 	    				data_t = data_t<<(index-32);
 	    				data_t |=  (uint64_t)((cdata<<(64-(index-32)))>>(64-(index-32)));
 	    				index = 0x5555;
 	    			}
 	    			else
 	    			{
 	        			for(uint8_t i=1;i<=rec;i++)
 	        			{
 	        				data_t = (data_t<<1)|((cdata>>(index-32-i))&1) ;
 	        			}

 	        			if(rec!= 33)
 	        			{
 	        				data_t = data_t ^ crc_poly;
 	        				index -= rec;
 	        			}
 	        			else
 	        			{
 	        				data_t = 0;
 	        				index_t = index-32-1;
 	        				index = 0xaaaa;

 	        			}

 	    			}

 	            }
 				if(index==0x5555) break;
 			}
 			else
 			{
 				index_t--;
 				if(index_t<32) break;
 			}
         }

 		if(cn>0) //next segment
 		{
  			cdata = data_t&0x00ffffffff;

 			for(uint8_t k=0;k<4;k++)
 			{
 	    		 cdata = (cdata<<8);
 	    		 cdata = cdata|datain[j++];

 			}

 	    	data_t = 0;
 	 		index_t = 63;  ///bit shifting index for initial '1' searching
 	 		index = 63;    //bit shifting index for CRC computing
 	 		rec = 0; //bit number needed to be compensated for next CRC computing
 		}

     }
     while(cn>0);

     free(datain);
     return (uint32_t)data_t;
}

CRC-32校验函数32位计算方式优化

在理解了和CRC32校验原理完全一致的代码实现后,不采用64位计算方式,则可以简化代码为32位计算方式,可得到相同的校验值结果:

#include <stdio.h>
#include <stdlib.h>
uint32_t PY_CRC_32_S(uint8_t *di, uint32_t len)
{
    uint32_t crc_poly = 0x04C11DB7;  //X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+1 total 32 effective bits without X^32. Computed total data shall be compensated 32-bit '0' before CRC computing.

	uint32_t clen = len+4;
	uint8_t cdata[clen] ;
	memcpy(cdata, di, len); cdata[len]=0; cdata[len+1]=0; cdata[len+2]=0; cdata[len+3]=0;
	uint32_t data_t =  (((uint32_t)cdata[0]) << 24) +  (((uint32_t)cdata[1]) << 16) + (((uint32_t)cdata[2]) << 8) + cdata[3]; //CRC register

    for (uint32_t i = 4; i < clen; i++)
    {
        for (uint8_t j = 0; j <= 7; j++)
        {
            if(data_t&0x80000000)
            	data_t = ( (data_t<<1) | ( (cdata[i]>>(7-j))&0x01) ) ^ crc_poly;
            else
            	data_t = ( (data_t<<1) | ( (cdata[i]>>(7-j))&0x01) ) ;
        }
    }
    return data_t;
}

CRC-32校验函数查表原理优化

CRC查表原理通过输入数据分段计算(CRC-32可按四字节/单字节分段)原理实现校验码的计算,查表法有如下特点:

  1. 当前输入数据段值异或当前的查表值,得到当前的CRC计算余数
  2. 当前查表值由前一计算余数与校验码按CRC校验过程计算得到,并保存为对应前一计算余数对应的表位值
  3. 当前查表值的计算不受当前输入字段值影响,所以当前输入字段值为0且为最后字段时,当前查表值异或当前输入字段值不变,此时当前查表值即为CRC校验值结果。
  4. 由第2和3条可知,第2条在CRC校验过程计算时,移位补位时补0即可,也就不需要当前字段值进入移位补位过程。

CRC-32校验32位数据格式函数优化为如下代码,注意输入数据为32位数组:

uint32_t PY_CRC_32_T32(uint32_t *di, uint32_t len)
{
	uint32_t crc_poly = 0x04C11DB7;  //X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+1 total 32 effective bits without X^32.
	uint32_t data_t = 0; //CRC register

    for(uint32_t i = 0; i < len; i++)
    {
    	data_t ^= di[i]; //32-bit data

        for (uint8_t j = 0; j < 32; j++)
        {
            if (data_t & 0x80000000)
            	data_t = (data_t << 1) ^ crc_poly;
            else
            	data_t <<= 1;
        }
    }
    return (data_t);
}

CRC-32校验8位数据格式函数优化为如下代码,输入数据为8位数组:

uint32_t PY_CRC_32_T8(uint8_t *di, uint32_t len)
{
	uint32_t crc_poly = 0x04C11DB7;  //X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+1 total 32 effective bits without X^32. 
	uint32_t data_t = 0; //CRC register

    for(uint32_t i = 0; i < len; i++)
    {
    	data_t ^= di[i]<<24; //8-bit data

        for (uint8_t j = 0; j < 8; j++)
        {
            if (data_t & 0x80000000)
            	data_t = (data_t << 1) ^ crc_poly;
            else
            	data_t <<= 1;
        }
    }
    return (data_t);
}

查表法对应输入数据分段为四字节时,采用如上几种方式任何一种,对四字节0~4294967295的输入数分别进行CRC-32校验,得到的各个校验值,也就得到查表法对应每个输入数值的查表值。因为这种表数据量太大不会被实际用
查表法对应输入数据分段为单字节时,采用如上几种方式任何一种,对单字节0~255的输入数分别进行CRC-32校验,得到的各个校验值,也就得到查表法对应每个输入数值的查表值。

CRC-32校验注意事项

实际应用中,由于输入数据前处理和输出数据后处理的不同,产生了不同的CRC应用标准,其中一些是一些知名厂家为自己的产品定义CRC校验函数。这些处理特性包括CRC寄存器初始值设置,数据字节位反转,数据字节高位还是低位优先进入计算,输出的整个数据是否按位反转,输出数据是否和一个数异或等。常见的一些CRC-32校验特性:
在这里插入图片描述
另外,ST公司STM32芯片硬件CRC32计算过程特性也和上述两种计算过程特性存在差别,所以计算结果。而这几种因为都有前处理和后处理过程特性,所以也和上面介绍的原理级定义的CRC32校验函数(无前后处理)计算出来的值不同。

CRC-32常用(事实标准)校验函数

CRC-32常用(事实标准)检验函数针对能够从硬件上进行比特流实时计算而设计,即每个数据的一位进来后马上就能进行CRC-32,而不必收全数据再计算。因此对应的软件CRC-32存在一些特点:

  1. 初始值预设为0xFFFFFFFF
    2.针对数据字节的低位先传输场景,因此数据字节的低位是高优先处理的
  2. 按照字节分段进行CRC-32计算,字节放在寄存器的低字节,因此字节最低位在左高由低的最右边一位,在进行CRC计算过程时,要从最低位/最右侧位置开始判断,移位时向右移出。因为校验码高冥端也要相应对齐,所以检验码也就要做倒位序,如0x04C11DB7(0000 0100 1100 0001 0001 1101 1011 0111)倒序为了0xEDB88320(1110 1101 1011 1000 1000 0011 0010 0000)
  3. 输出异或0xFFFFFFFF

CRC-32常用(事实标准)校验函数为反向算法(反向算法是从由右向左计算,也即计算过程中移位时,向右移出。):

uint32_t PY_CRC_32_M(uint8_t *di, uint32_t len)
{
    uint32_t crc_poly = 0xEDB88320;  //Inversion bit sequence of 0x04C11DB7
	uint32_t data_t = 0xFFFFFFFF; //initial value

	for(uint32_t i=0; i<len; i++)
	{
		data_t ^=  di[i];
        for (int8_t j = 8; j > 0; --j)
        {
        	data_t = (data_t >> 1) ^ ((data_t & 1)? crc_poly: 0);
        }
	}
	return data_t ^ 0xFFFFFFFF;
}

对"CRC32”的计算结果为:
在这里插入图片描述

通过网上工具验证:
在这里插入图片描述
–End–

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/423082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML5 <ol> 标签、HTML5 <object> 标签

HTML5 <ol> 标签 实例 HTML5 <ol>标签用于定义文档中的有序列表。请参考下述示例&#xff1a; 2 个不同的有序列表实例&#xff1a; <ol><li>Coffee</li><li>Tea</li><li>Milk</li> </ol><ol start"50…

低代码平台是否会取代程序员?答案在这里

上图是一张机器人或者自动化系统取代人工的图片&#xff0c;您看了有哪些感想呢&#xff1f; 故事 程序员小张&#xff1a; 刚毕业&#xff0c;参加工作1年左右&#xff0c;日常工作是CRUD 架构师老李&#xff1a; 多个大型项目经验&#xff0c;精通各种屠龙宝术&#xff1b; …

Java 在线编程编译工具上线,直接运行Java代码

前言 大家好&#xff0c;我是小哈~ 周末没出去浪&#xff0c;花了点时间&#xff0c;在我的个人网站上线了一款小工具。啥工具呢&#xff1f;一款可以在线编译 Java 代码并运行输出结果的小工具。 大家都知道&#xff0c;甲骨文刷 Java 版本号非常积极&#xff0c;这不上个月…

【大唐杯学习超快速入门】5G技术原理仿真教学——通信网络认知

这里写目录标题智能通信业务对讲机固定电话电视机wifiPAD扫地机器人手机电信业务号码办理基础业务办理业务选择通信流程模拟增值业务办理工程实践信号塔基站机房传输&核心机房智能通信业务 按照顺序来进行&#xff0c;对讲机&#xff0c;固定电话&#xff0c;电视机&#…

HTTP协议 | 一文详解HTTP报文结构

目录 &#x1f333; HTTP/HTTPS简介 &#x1f333; HTTP工作原理 HTTP三点注意事项 1. HTTP是无连接的 2. HTTP是媒体独立的 3. HTTP是无状态的 HTTPS 作用 &#x1f333; HTTP消息结构 HTTP请求消息 1. 请求行 2. 请求头 3. 空行 4. 请求数据 HTTP请求实例 HTT…

中电金信:数字化转型|银行业数据中心数字化转型之驱动篇

导语&#xff1a; 在新基建和国产化创新的推动下&#xff0c;银行业掀起了数字化转型的浪潮。但在众多银行中&#xff0c;数字化转型仍旧停留在业务层面&#xff0c;数据中心的数字化转型一直处于配合和被动应对。数据中心层面的数字化转型如何开展&#xff0c;数据中心数字化…

springboot的rest服务配置服务的根路径

如果不配置默认为空&#xff0c;如下是application.yml文件只配置了端口号 server:port: 6868 那么访问时直接访问服务即可 如果配置了rest服务 RestController RequestMapping("/netLicense") public class NetLicenseController {RequestMapping("/getLice…

BP神经网络和RBF神经网络的区别

本站原创文章&#xff0c;转载请说明来自《老饼讲解-BP神经网络》 bp.bbbdata.com 有些同学只学过BP神经网络&#xff0c;想了解RBF神经网络 或者只学过RBF神经网络&#xff0c;想了解BP神经网络 那么本文就非常适合这些同学阅读&#xff0c;帮助大家快速将相关知识迁移到BP/RB…

Java——二叉树的镜像

题目链接 leetcode在线oj题——二叉树的镜像 题目描述 请完成一个函数&#xff0c;输入一个二叉树&#xff0c;该函数输出它的镜像。 例如输入&#xff1a; 4 / 2 7 / \ / 1 3 6 9 镜像输出&#xff1a; 4 / 7 2 / \ / 9 6 3 1 题目示例 输入&#xff1a;root [4,2…

sql的左连接(LEFT JOIN)、右连接(RIGHT JOIN)、内连接(INNER JOIN)的详解

sql的左连接&#xff08;LEFT JOIN&#xff09;、右连接&#xff08;RIGHT JOIN&#xff09;、内连接&#xff08;INNER JOIN&#xff09;的详解&#xff1a; 这里以两个表的连表为例&#xff1a; 创建表1&#xff1a;为人员表&#xff0c;这里将它当做左表&#xff1b; CREA…

如何配置达梦数据库使其支持GB18030-2022中文编码字符集

达梦版本要求&#xff0c;要求使用2023年4月及之后的达梦月度版版本&#xff0c;补丁版、临时版等不可以。正确安装windows操作系统&#xff0c;windows10以下的版本未做过测试&#xff0c;可能系统不支持导致各种显示错误&#xff0c;建议用windows10及以上版本&#xff0c;本…

大数据能力提升项目|学生成果展系列之六

导读为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

分子生物学 第一章 概论

文章目录第一章 概论1.1.1分子生物学的概念以及发展简史1.2.1分子生物学研究概况第一章 概论 1.1.1分子生物学的概念以及发展简史 广义的定义&#xff1a; 在分子水平上解释生物学现象。 &#xff08;难以与生物化学区分&#xff09; 严格的定义&#xff1a; 在分子水平上研究…

2023年就业卷,卷,卷!前端面试怎么准备?

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;张轩|慕课网讲师 大多数开发者应该都经历过跳槽和面试&#xff0c;这也是我们工作生活中必须要经历的一部分&#xff0…

关于Python爬虫使用技巧

首先&#xff0c;Python是一种非常流行的编程语言&#xff0c;拥有广泛的应用领域&#xff0c;例如数据分析、人工智能、Web开发等。如果您是初学者&#xff0c;可以开始学习基础的语法和概念&#xff0c;例如变量、数据类型、循环、函数等等。许多在线资源可以提供学习资料。 …

主题切换实现(vue-less)

介绍 本文适合黑白切换或者主题样式偏少的&#xff08;建议&#xff1a;2-10种&#xff09;&#xff1b;主题越多&#xff0c;样式会越多。理论上无限套。本文适合已经写好了一套主题&#xff0c;然后需求增加第二套或者多套主题&#xff08;最好小于10套&#xff0c;当然也可…

免费送30张可视化大屏,跳过复杂代码,轻松缔造可视化智慧校园

“现在老师和学校管理的信息化做的特别差&#xff01;” 。 当我做智慧校园软硬件的老同学和我这么说时&#xff0c;我惊呆了。他认为现在的大多数开发商大部分打着“智慧校园”的旗号&#xff0c;但是所做的系统仅仅是门禁刷卡&#xff0c;或者校园一卡通系统&#xff0c;请问…

视觉检测系统是怎么检测尺寸的?

随着科学技术的进步和市场通知的发展越来越多的自动化机器正在代替人工。 视觉检查系统也是如此。 视觉检测系统在许多行业的应用越来越热衷。 如工业五金. 3c电子.纺织等行业。 那么&#xff0c;具体而言&#xff0c;什么是视觉尺寸检测呢&#xff1f; 1 .什么是尺寸检查&am…

【RabbitMQ】初识消息中间件MQ

目录 一、什么是MQ 二、MQ的优缺点 1、MQ的优点 1.应用解耦 2.削峰填谷 3.异步提速 2、MQ的缺点 1.可用性低 2.系统复杂度高 3.数据一致性问题 三、MQ使用场景 四、常见的MQ 一、什么是MQ MQ&#xff08;Message Queue&#xff09;&#xff1a;消息队列&#xff0c…

为什么多线程读写 shared_ptr 要加锁?

陈硕&#xff08;giantchen_AT_gmail_DOT_com&#xff09; 2012-01-28 我在《Linux 多线程服务端编程&#xff1a;使用 muduo C 网络库》第 1.9 节“再论 shared_ptr 的线程安全”中写道&#xff1a; &#xff08;shared_ptr&#xff09;的引用计数本身是安全且无锁的&#…