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

news2024/11/17 11:32:39

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

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

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

设计原理

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

CRC-16校验函数

这里的校验码采用标准校验码X^16 + X^15 + X^2 + 1,对于其它类型的CRC-16校验码或有输入数据前处理或输出数据后处理的情况,相应的做代码简单调整即可。CRC-16校验函数如下:

#include <stdio.h>
#include <stdlib.h>
uint16_t PY_CRC_16(uint8_t *di, uint32_t len)
{   
    uint32_t crc_poly = 0x00018005;  //X^16+X^15+X^2+1 total 17 effective bits. Computed total data shall be compensated 16-bit '0' before CRC computing.

	uint8_t *datain;
	uint64_t cdata = 0; //Computed total data
    uint32_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+2)/6;
    uint32_t cr=(len+2)%6;

	uint32_t j;

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

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

         }
         else if(cr==2)
         {
             cr = 8;

         }
    	 else
    	 {
    		 cn++;
    	 }

    	 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-16));
 				{
 					data_t = data_t ^ crc_poly;
 				}

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

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

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

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

 	        			}

 	    			}

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

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

 			for(uint8_t k=0;k<6;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 (uint16_t)data_t;
}

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

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

#include <stdio.h>
#include <stdlib.h>
uint16_t PY_CRC_16_S(uint8_t *di, uint32_t len)
{
    uint16_t crc_poly = 0x8005;  //X^16+X^15+X^2+1 total 16 effective bits without X^16. Computed total data shall be compensated 16-bit '0' before CRC computing.

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

    for (uint32_t i = 2; i < clen; i++)
    {
        for (uint8_t j = 0; j <= 7; j++)
        {
            if(data_t&0x8000)
            	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-16校验函数查表原理优化

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

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

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

uint16_t PY_CRC_16_T16(uint16_t *di, uint32_t len)
{
	uint16_t crc_poly = 0x8005;  //X^16+X^15+X^2+1 total 16 effective bits without X^16. 
	uint16_t data_t = 0; //CRC register

	uint16_t cdata[len];
	for(uint32_t j=0;j<len;j++)
	{
		cdata[j] = (di[j]>>8 | di[j]<<8);
	}
	cdata[0] ^= 0xffff;

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

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

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

uint16_t PY_CRC_16_T8(uint8_t *di, uint32_t len)
{
	uint16_t crc_poly = 0x8005;  //X^16+X^15+X^2+1 total 16 effective bits without X^16. 
	uint16_t data_t = 0; //CRC register

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

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

        }
    }
    return (data_t);
}

查表法对应输入数据分段为双字节时,采用如上几种方式任何一种,对双字节0~65535的输入数分别进行CRC-16校验,得到的各个校验值,也就得到查表法对应每个输入数值的查表值。
查表法对应输入数据分段为单字节时,采用如上几种方式任何一种,对单字节0~255的输入数分别进行CRC-16校验,得到的各个校验值,也就得到查表法对应每个输入数值的查表值。

CRC-16校验注意事项

实际应用中,由于输入数据前处理和输出数据后处理的不同,产生了不同的CRC应用标准,其中一些是一些知名厂家为自己的产品定义CRC校验函数。这些处理特性包括CRC寄存器初始值设置,数据字节位反转,数据字节高位还是低位优先进入计算,输出的整个数据是否按位反转,输出数据是否和一个数异或等。常见的一些CRC-16校验特性:

在这里插入图片描述
–End–

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

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

相关文章

48.现有移动端开源框架及其特点—MDL(mobile-deep-learning)

48.1 功能特点 一键部署,脚本参数就可以切换ios或者android支持iOS gpu运行MobileNet、squeezenet模型已经测试过可以稳定运行MobileNet、GoogLeNet v1、squeezenet、ResNet-50模型体积极小,无任何第三方依赖。纯手工打造。提供量化函数,对32位float转8位uint直接支持,模型…

嵌套列表,与摩尔投票进阶

title: “Python fishC 22” author: “hou wei” date: “2023-04-16” output: html_document knitr::opts_chunk$set(echo TRUE)问答题 0.请问 运算符和 is 运算符有什么区别呢&#xff1f; 在Python中运算符用于比较两个变量的值是否相等&#xff0c;而is运算符用于判断…

2023年MathorCup数模A题赛题详细思路

MathorCup俗称妈杯&#xff0c;是除了美赛国赛外参赛人数首屈一指的比赛&#xff0c;而我们的妈杯今天也如期开赛。今年的妈杯难度&#xff0c;至少在我看来应该是2023年截至目前来讲最难的一场比赛。问题的设置、背景的选取等各个方面都吐露着我要难死你们的想法。难度是恒定的…

MySQL-自带工具介绍

目录 &#x1f341;mysql &#x1f341;mysqladmin &#x1f990;博客主页&#xff1a;大虾好吃吗的博客 &#x1f990;MySQL专栏&#xff1a;MySQL专栏地址 MySQL数据库不仅提供了数据库的服务器端应用程序&#xff0c;同时还提供了大量的客户端工具程序&#xff0c;如mysql&a…

elasticsearch——自动补全

拼音分词器 当用户在搜索框输入字符时&#xff0c;我们应该提示出与该字符有关的搜索项&#xff0c;如图&#xff1a; 要实现根据字母做补全&#xff0c;就必须对文档按照拼音分词。在GitHub上恰好有elasticsearch的拼音分词插件。地址&#xff1a; GitHub - medcl/elasticse…

考研数二第十六讲 不定积分-换元积分和分部积分以及有理函数的积分

第一类换元积分法——凑微分法 假设现在我们要对一个复合函数f[g(x)] 求不定积分&#xff0c;但我只有∫f(x)dxF(x)\int f(x)dx F(x)∫f(x)dxF(x) 这一积分公式。这时候就要想&#xff0c;要是中括号里不是g(x) 而是 x该多好啊。 如果我直接令ug(x) &#xff0c;强行让原式变…

Redis 如何使用 Twemproxy 和 Sentinel 构建高可用集群架构?

文章目录Redis 如何使用 Twemproxy 和 Sentinel 构建高可用集群架构&#xff1f;配置环境构建 RedisSharding1安装 Redis配置 RedisSharding1构建 RedisSharding2安装 Redis配置 RedisSharding2构建 Sentinel Cluster配置 Sentinel启动 Sentinel构建 Twemproxy Cluster安装 Twe…

AI 腾讯云人脸核身之独立H5接入

一、概述 人脸识别&#xff0c;使用官方API&#xff1a;腾讯云人脸核身之独立H5接入。接口官方返回code 0 表示成功,其他code码值均为对应码值信息&#xff0c;详见错误码。 注意&#xff1a; 1.合作方上送身份信息的计算签名参数与启动人脸核身计算签名参数不一致&#xff0…

Python-DQN代码阅读(13)

目录 1.代码 1.1 代码阅读 1.2 代码分解 1.2.1 导入库 1.2.2 data np.loadtxt(performance.txt) 1.2.3 mva np.zeros((data.shape[0]), dtypenp.float) 1.2.4 mva[i] data[i,1]&#xff0c;mva[i] alpha * data[i,1] (1.0 - alpha) * mva[i-1] 1.2.5 plt.plot(data…

【C++项目】高并发内存池

前言&#xff1a; 本篇博客大致记录基于tcmalloc实现高并发内存池的思想与实现方案。 使用语言&#xff1a;C&#xff0c;编译器&#xff1a;vs2022&#xff0c;开始时间&#xff1a;2023/4/3&#xff0c;结束时间&#xff1a;2023/4/12。 项目源码地址&#xff1a;Cproject: 我…

第八天并发编程篇

一、简述线程、进程、程序的基本概念&#xff1f; 1.进程&#xff1a; 我们把运行中的程序叫做进程,每个进程都会占用内存与CPU资源,进程与进程之间互相独立. 2.线程&#xff1a; 线程就是进程中的一个执行单元&#xff0c;负责当前进程中程序的执行。一个进程可以包含多个线程…

【电子秤方案】LCD口袋秤芯片方案

LCD高精度口袋电子秤方案&#xff0c;即便携式称重仪&#xff0c;是一种应用于生活中的称重设备。便珠宝秤具有体积小、重量轻、功耗低、结构紧凑等特点。 LCD高精度口袋电子秤方案产品简介 口袋电子秤是一种体积小、重量轻、功耗低&#xff0c;可用于多种场合的电子秤。它通常…

如何检查 Linux 内存使用量是否耗尽?这5个命令堪称绝了!

在 Linux 操作系统中&#xff0c;内存是一个关键资源&#xff0c;用于存储正在运行的程序和操作系统本身的数据。如果系统的内存使用量过高&#xff0c;可能会导致性能下降、应用程序崩溃或者系统崩溃。因此&#xff0c;了解如何检查 Linux 内存使用量是否耗尽是非常重要的。下…

【网络安全】文件上传绕过思路

引言 分享一些文件上传绕过的思路&#xff0c;下文内容多包含实战图片&#xff0c;所以打码会非常严重&#xff0c;可多看文字表达&#xff1b;本文仅用于交流学习&#xff0c; 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人…

什么是划分子网?网络工程师划分子网有啥技巧?

随着互联网的快速发展&#xff0c;越来越多的组织和企业在其内部建立了复杂的网络系统来满足日常的信息传输和资源共享需求。而在这些网络系统中&#xff0c;划分子网&#xff08;也称为子网划分&#xff09;作为一种常见的网络管理方法&#xff0c;为组织和企业提供了更加灵活…

【面试】记一次安恒面试及总结

文章目录SQL 注入sql注入的原理&#xff1f;如何通过SQL注入判断对方数据库类型&#xff1f;补充一下其他方法判断数据库类型时间盲注的函数XPath注入抓不到http/https包&#xff0c;怎么办&#xff1f;app无自己的ssl证书app有自己的ssl证书-证书绑定(SSL pinning)逻辑漏洞有哪…

【学习笔记】滑动窗口

acwing.滑动窗口https://www.acwing.com/problem/content/156/ 给定一个大小为 n≤106≤106 的数组。 有一个大小为 k 的滑动窗口&#xff0c;它从数组的最左边移动到最右边。 你只能在窗口中看到 k 个数字。 每次滑动窗口向右移动一个位置。 以下是一个例子&#xff1a; …

Python使用Opencv进行图像人脸、眼睛识别实例演示

效果展示 下面使用 haarcasecade_eye.xml 进行人眼识别的效果图&#xff1a; 人脸识别是一种可以自动检测图像或视频中存在的人脸的技术。它可以用于各种应用&#xff0c;例如安全控制&#xff0c;自动标记照片和视频&#xff0c;以及人脸识别解锁设备等。在这篇博客中&#…

水声功率放大器模块基于通道接收和发射的水声通信机的应用

实验名称&#xff1a;基于多通道接收和发射的水声通信机 研究方向&#xff1a;水声通信 测试设备&#xff1a;数模转化器、ATA-ML180水声功率放大器模块、示波器、接收换能器、发射换能器等。 图&#xff1a;实验原理 一、发射机的双通道发送实验&#xff1a; 实验过程&#xf…

Redis与本地缓存组合使用(IT枫斗者)

Redis与本地缓存组合使用 前言 我们开发中经常用到Redis作为缓存&#xff0c;将高频数据放在Redis中能够提高业务性能&#xff0c;降低MySQL等关系型数据库压力&#xff0c;甚至一些系统使用Redis进行数据持久化&#xff0c;Redis松散的文档结构非常适合业务系统开发&#xf…