CRC校验(2):CRC32查表法详解、代码实现和CRC反转

news2024/11/22 16:53:13

对于现在的CPU来说,基本上都在硬件上实现了CRC校验。但我们还是想用软件来实现一下CRC的代码,这样可以更深入地理解里面的原理。所以这一节就来详细地解释如何使用查表法从软件上来实现CRC-32的校验。另外,CRC还有一种反转的情况,实际上反转和不反转没有什么太大的区别,主要是需求和标准的不同。

文章目录

  • 1 找规律
  • 2 查表法原理
  • 3 CRC32代码C语言实现
    • 3.1 CRC32表格生成
    • 3.2 CRC查表代码实现
  • 4 CRC反转
    • 4.1 CRC32的标准反转函数
    • 4.2 CRC输入/输出反转

1 找规律

再来看一下上一节中的例子,被除数为100100,除数为1101的计算过程:
在这里插入图片描述
我们来找一下规律,思考一下在计算机中应该如何实现。不难发现以下规律:

  • 除数的最高位一定是1,因为我们用的是它所代表的多项式的最高阶组成的数字
  • 对于除数来说,如果它的最高位不是1的话,就"除不动",什么都不做,左移一位,继续判断。
  • 由于做的是异或运算,所以当前的结果不一定要"减得动"被除数,只需要满足除数最高位为1,就和被除数做异或运算,然后再左移一位

2 查表法原理

如果我们要软件上实现CRC的话,要一位一位的做这些运算,效率是非常低的,所以我们就想能不能每8位计算一次,因为每个特定的数字与这个被除数的经过8次移位操作得到的异或结果都是相同的。
(1)为什么不每16位计算一次?
这样就要保存 2 16 2^{16} 216个uint16_t类型的数据,一个表格就有128KB,这比很多单片机的Flash要大了
(2)每8位计算一次的理论依据是什么
我们知道 C R C ( 0 ) = 0 CRC(0)=0 CRC(0)=0,然后由前面分析出的特性,我们可以推导出这个公式: C R C ( A + B ) = C R C ( A ) + C R C ( B ) CRC(A+B) = CRC(A) + CRC(B) CRC(A+B)=CRC(A)+CRC(B)

现在举个例子,假如我们想求 C R C ( 0 × a b c d e f 12 ) CRC(0×abcdef12) CRC(0×abcdef12),他就可以等价于:
C R C ( 0 × a b c d e f 12 ) = C R C ( 0 × a b 000000 ) + C R C ( 0 × 00 c d e f 12 ) = C R C ( 0 × a b ) + C R C ( 0 × c d ) + C R C ( 0 × e f ) + C R C ( 0 × 12 ) CRC(0×abcdef12) = CRC(0×ab000000) + CRC(0×00cdef12) = CRC(0×ab) + CRC(0×cd) + CRC(0×ef) + CRC(0×12) CRC(0×abcdef12)=CRC(0×ab000000)+CRC(0×00cdef12)=CRC(0×ab)+CRC(0×cd)+CRC(0×ef)+CRC(0×12)

假如我们定义一个8位的查表表格,这样我们就可以把本来每次要进行的32次移位和异或的运算缩短为了4次。

3 CRC32代码C语言实现

3.1 CRC32表格生成

经过前面的分析,我们知道,我们就是需要给uint8_t范围内(0~255)的每一个数做一下模二除法,然后将得到的结果保存到一个类型为uint8_t、大小为256的表格中。我们只需要判断CRC的最高位是否为1,若为0则左移一位,若为1则先将crc左移1位,然后和多项式做异或运算。CRC32表格生成代码如下:

void GenerateTable(uint32_t polynomial)
{
	for (int byte = 0; byte < 256; ++byte)
	 {
		uint32_t crc = byte;
		
		for (int bit = 32; bit > 0; --bit)
		{
			if (crc & 0x80000000)
			{
				  crc = (crc << 1) ^ polynomial;
			}
			else
			{
				  crc <<= 1;
			}
		}
		crcTable[byte] = crc;
	 }
}

如果你把上面的代码和前面的例子那张图做对比的话,我相信不少人会想为什么在CRC最高位为1的时候,执行的不是crc = (crc ^ polynomial) << 1

别忘了,对于CRC32来说,它的多项式所对应的二进制是有33位的,实际上我们无法用一个uint32_t的变量来保存这个多项式。但是我们知道,CRC32的多项式的最高位一定是1,所以这里我们就保存低32位作为polynomial。当代码中CRC的最高位为1时,它与CRC32的最高位异或的结果也一定是0。所以这里就先将CRC右移一位,然后与多项式异或,这样循环32次,就得到在多项式polynomial下的byte所对应的CRC,将其存入crcTable中。

3.2 CRC查表代码实现

有了前面的表格,我们使用下面的函数就能计算长度为len的字符串msg的CRC32了,在循环中,将CRC的高八位所对应的数在CRC32表格中的结果与上次计算出来的CRC右移八位的结果进行异或,最后就得到了这个字符串的CRC结果了。

unsigned int calcMsgCRC(char *msg, unsigned int len)
{
    unsigned long crc = 0;
    for (int n = 0; n < len; n++)
    {
    	uint8_t c = msg[n] & 0xff;
        crc = crcTable[(crc >> 24) ^ c] ^ (crc << 8);
    }
    return crc;
}
  • 在某些协议的CRC算法中,CRC有一个固定的初始值,求出来CRC结果后也还需要异或一个固定数

另外,在有些场合下,比如从串口中获取最新的固件来升级系统,固件的完整性也通过CRC校验。在有的设备中没有那么大的内存将整个buffer保存下来,再计算整个buffer的CRC校验。对于这种情况,我们可以一段一段地计算CRC,然后将前一次CRC的结果赋值给函数中unsigned long crc的初始值。也就是calcMsgCRC函数的参数也要多加一个lastCRC

  • 我之前从NXP SDK提取了一个分段CRC的代码,大家也可以用这个框架:C语言 CRC32分段计算实现

4 CRC反转

有时你可能会发现一些标准协议的CRC的表格和你生成的就是不一样。这可能是因为CRC有两种实现方式:

  • 非反转CRC:数据的每一位从最高位到最低位依次处理
  • 反转CRC:数据的每个字节或比特位的处理顺序可以根据需求进行反转。

4.1 CRC32的标准反转函数

对于这个反转的定义我一直没有找到,但我找到了代码,所以还是从代码中来理解一下,所谓的反转函数是如何反转的。

  • 当然,这些反转都可以自己定义,比如小端的CRC你转成大端的,每一位反转等。这里介绍的反转方法是在一些知名的协议中使用的CRC算法中用到的。
uint32_t Reverse(uint32_t value)
{
  value = ((value & 0xAAAAAAAA) >> 1) | ((value & 0x55555555) << 1);
  value = ((value & 0xCCCCCCCC) >> 2) | ((value & 0x33333333) << 2);
  value = ((value & 0xF0F0F0F0) >> 4) | ((value & 0x0F0F0F0F) << 4);
  value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
  value = (value >> 16) | (value << 16);
  return value;
}

(1)将value的奇数位和偶数位分别取出,并将奇数位右移1位,偶数位左移1位,然后将它们进行按位或运算。这样可以交换奇数位和偶数位的值。
(2)将value的每2位分组,其中每组的高位和低位进行比特顺序的反转。同样,采用按位与和按位或运算,将高位和低位进行交换。
(3)将value的每4位分组,同样对每组的高位和低位进行比特顺序的反转。
(4)将value的每8位分组,同样对每组的高位和低位进行比特顺序的反转。
(5)将value的高16位和低16位进行比特顺序的反转

4.2 CRC输入/输出反转

另外,我们可以选择对CRC在输入时反转,也可以选择对CRC在输出时反转,当然也可以选择都反转。所以这时候反转CRC32表格生成函数需要做小小的修改:

void GenerateTable(uint32_t polynomial, bool reflectIn, bool reflectOut)
{
    for (int byte = 0; byte < 256; ++byte)
    {
        uint32_t crc = (reflectIn ? (Reverse(uint32_t(byte)) >> 24) : byte);

        for (int bit = 32; bit > 0; --bit)
        {
            if (crc & 0x80000000)
            {
                crc = (crc << 1) ^ polynomial;
            }
            else
            {
                crc <<= 1;
            }
        }
        crcTable[byte] = (reflectOut ? Reverse(crc) : crc);
    }
}

对于反转CRC的计算函数来说(假设输入和输出都反转),要这样修改:

unsigned int calcMsgCRCReverse(char *msg, unsigned int len)
{
    unsigned long crc = 0;
    for (int n = 0; n < len; n++)
    {
        uint8_t c = msg[n] & 0xff;
        c = Reverse(c);
        crc = crcTable[(crc ^ c) & 0xFF] ^ (crc >> 8);
    }
    return Reverse(crc);
}

使用反转CRC或非反转CRC时,CRC表格的生成和查找方法也会有所不同。这两种方式在实际应用中并没有明显的性能或准确性差异,选择哪种方式主要取决于应用的需求和标准。

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

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

相关文章

SpringCloud Ribbon负载均衡(十一)

前面搭建了初步例子&#xff0c;但是还没实现真正负载均衡&#xff0c;我们这里要先搞三个服务提供者集群&#xff0c;然后才能演示负载均衡&#xff0c;以及负载均衡策略&#xff1b; 新建项目microservice-student-provider-1002&#xff0c;microservice-student-provider-…

行星减速机优势有哪些?行星减速机五大优势

减速机是动力传动解决方案&#xff0c;通过选择高质量和高效率的变速箱&#xff0c;绝对可以提高整个动力传动系统的效率和性能。行星减速机有哪些优势呢&#xff1f; 1.保证灵活可靠的动力传动系统 减速机提供了广泛的功率和比率&#xff0c;使其成为许多行业的大多数应用的完…

代码随想录2刷|链表1.链表理论基础2移除链表元素3.设计链表4.翻转链表5.两两交换链表中的节点6.删除链表的倒数第N个节点7.链表相交8.环形链表lI

2移除链表元素 链接&#xff1a;力扣 一刷&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x…

Vue中如何进行地理位置搜索与地点选择

Vue中如何进行地理位置搜索与地点选择 随着移动互联网和定位技术的普及&#xff0c;地理位置搜索和地点选择成为了很多应用程序中必不可少的功能。在Vue中&#xff0c;我们可以使用一些开源的地图API和第三方组件来实现这些功能。本文将介绍如何在Vue中进行地理位置搜索和地点…

【北邮国院大三下】Logistics and Supply Chain Management 物流与供应链管理 Week3

北邮国院大三电商在读&#xff0c;随课程进行整理知识点。仅整理PPT中相对重要的知识点&#xff0c;内容驳杂并不做期末突击复习用。个人认为相对不重要的细小的知识点不列在其中。如有错误请指出。转载请注明出处&#xff0c;祝您学习愉快。 如需要pdf格式的文件请私信联系或…

gradlew test 失败

前言 在idea内执行./gradlew test&#xff0c;发现如下报错&#xff1a; Could not initialize class org.codehaus.groovy.runtime.InvokerHelper 分析 google了一堆&#xff0c;说要用groovy&#xff0c;可是我没有用groovy&#xff0c;以前也是正常启动的。后来无意发现&a…

游戏玩家的新大陆?小红书游戏内容场景洞察

2023年&#xff0c;如果你问年轻人他们在哪里讨论游戏&#xff1f;他们可能会提到一些平台&#xff0c;比如Steam、TapTap、B站、微博或者论坛。但是如果你向身边的女孩子询问&#xff0c;她们可能会惊喜地告诉你&#xff1a;小红书。 小红书平台一直给人的标签是是“美妆、旅…

UWB高精度实时定位系统源码(springboot+vue)

一、系统概况 UWB&#xff08;Ultra-wideband&#xff09;技术是一种无线载波通讯技术&#xff0c;它不采用正弦载波&#xff0c;而是利用纳秒级的非正弦波窄脉冲传输数据&#xff0c;因此其所占的频谱范围很宽。自主研发&#xff0c;最高定位精度可达10cm&#xff0c;具有高精…

数据库架构是否该随着公司估值一起变化?

原文&#xff5c;The growing pains of database architecture 作者&#xff5c;Tim Liang, Software Engineer at Figma 2020 年&#xff0c;因为 Figma 不断加入新功能&#xff0c;筹备第二条产品线和用户不断增长导致数据库流量每年以 3x 速度增长&#xff0c;我们的基础设…

将数组中指定位置的元素替换为指定值np.put()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将数组中指定位置的元素替换为指定值 np.put() 选择题 下列说法错误的是? import numpy as np a np.array([1, 2, 3]) print("【显示】a ", a) print("【执行】np.put(arr…

Spring Boot进阶(47):Spring Boot之集成Cache缓存 | 超级详细,建议收藏

1. 前言 今天&#xff0c;我们来聊聊缓存这个话题。身为开发者肯定都知道&#xff0c;程序的瓶颈绝大体现在于数据库方面&#xff0c;而内存读取远远快于硬盘&#xff0c;当并发上升到一定高度&#xff0c;一次又一次的重复请求数据导致大量时间耗费在数据库查询上&#xff0c;…

win10搭建hmailserver邮件服务器(hmailserver+phpstudy+roundcube)

环境安装&#xff1a;Mysqlhmailserverphpstudyroundcube 一、Mysql安装 官网下载链接&#xff1a;https://www.mysql.com/ zip安装包下载链接&#xff1a;https://dev.mysql.com/downloads/mysql/ 1、zip安装包安装 &#xff08;1&#xff09;下载合适版本的mysql zip包&…

LeetCode------ 相交链表

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;栏目介绍:<<刷题集>>用于记录,力扣,牛客等刷题网站上的刷…

EasyExcel 批量导出

文章目录 前言一、EasyExcel 导出封装二、食用步骤1.自定义excel样式2.导出数据 三、复杂excel导出3.1. 自定义复杂表头2. 多sheet 前言 上篇写了数据导入&#xff0c;本文补充一下EasyExcel 批量导出 包括常规excel和复杂excel 一、EasyExcel 导出封装 import com.alibaba.…

手把手教你如何解开安装UKUI的黑屏故障

手把手教你如何解开安装UKUI的黑屏故障 引子 作为一个不折腾不舒服斯基的Linuxer&#xff0c;我又开始安装配置开放欧拉操作系统了。这是国产自主安全可控的Linux发行版。欧拉发行版Linux的发起者就是干正经事的华为&#xff0c;比其它拉大旗扯虎皮的国产Linux低调务实多了。…

远程控制之原理和实战

按理来说&#xff0c;本人不该发表此类专业文章&#xff0c;鄙人零星碎片化的开发经历&#xff0c;让本人斗胆向诸位网友&#xff0c;在远控方面做一点演示说明&#xff0c;谈论一点自己的认识。 程序工程代码地址&#xff1a;点击此处下载。 程序分为两个部分&#xff0c;控…

(三)Kafka 生产者

文章目录 1. Kafka 发送消息的主要步骤2.创建 Kafka 生产者3.发送消息到 Kafka&#xff08;1&#xff09;发送并忘记&#xff08;2&#xff09;同步发送&#xff08;3&#xff09;异步发送 4.生产者配置&#xff08;1&#xff09;client.id&#xff08;2&#xff09;ack&#x…

查看P端日志操作步骤

1.登录PUTTY,这里以联调环境103.160.139.82为例。 2.登录&#xff0c;查看用户名&#xff1a;hxb或zzkpt,密码&#xff1a;用户名01动态口令。 例如hxb, sunmenglei01888888 3.进入P端日志存放目录&#xff0c; cd /home/zzkpt/logs/bcip 4.比如我要查看2023年5月5日&#xf…

索引常见问题

被问到SQL和索引优化问题&#xff0c;如何切入&#xff1f; 可以用 explain 进行分析 思考流程&#xff1a;找到哪些运行时间长浪费性能的sql&#xff0c;然后再用explain分析 慢查询日志 MySQL可以设置慢查询日志&#xff0c;当SQL执行的时间超过我们设定的时间&#xff0…

在UE中使用SVT(VirtualTexture)功能

前几年VT技术非常的火&#xff0c;这项技术主要运用在地形上&#xff0c;可以达到更高级别的精细度和更多次数的纹理混合&#xff0c;但实际非地形也可以用&#xff0c;特别是对于贴图尺寸比较大且多维度子材质比较多的模型&#xff0c;做了材质合并以及VT优化后&#xff0c;可…