CRC校验算法的解析,暨对网上的CRC详解的补充

一、CRC的形象理解

本文面向对CRC校验有一定基础的读者,如果你不懂,请戳这里。维基百科还有图解版的。

在CRC的具体实现中,如果要计算CRC的数据很长,一般都会用到寄存器,用来保存当前的计算到的CRC,循环计算到数据流结束,以下给出了计算16位CRC的流程:(流程来源)

假如数据流为4字节:BYTE[3]、BYTE[2]、BYTE[1]、BYTE[0];

1)数据流左移16位,低位补0,将扩大后的数据流(6字节)高16位(BYTE[3]、BYTE[2])放入一个长度为16的寄存器;
2)如果寄存器的首位为1,将寄存器左移1位(寄存器的最低位从下一个字节获得),再与生成多项式的简记式异或;
    否则仅将寄存器左移1位(寄存器的最低位从下一个字节获得);
3)重复第2步,直到数据流(6字节)全部移入寄存器;
4)寄存器中的值则为CRC校验码CRC[1]、CRC[0]。

但是这种方式有个缺点,就是如果在被计算CRC的数据前即使出现了任意个0,会得到相同的CRC,也就是被除数前面加好多个0,除以多项式之后得到的余数还是不变。那么CRC校验就无法检测出这种类型的数据修改了。。

于是真正实现CRC还引进了寄存器的预设值(Preset),寄存器一开始的值一般不为0。

网上有人自己手算了A的16-bit CRC-CCITT,它就是相当于将预设值设为了0xFFFF,注意这里是将预置值直接放到数据的前面,然后进行手算,和下面讲的预处理有出入(来源)

Calculation of the 16-bit CRC-CCITT for a one-byte message consisting of the letter “A”:

                         Quotient=  111100001110111101011001 
      poly=       ------------------------------------------ 
10001000000100001 ) 1111111111111111010000010000000000000000 
                    10001000000100001 
                    -----------------       red bits are initial value 
                     11101111110111111      bold bits are message 
                     10001000000100001      blue bits are augmentation 
                     ----------------- 
                      11001111100111100 
                      10001000000100001 
                      ----------------- 
                       10001111000111010 
                       10001000000100001 
                       ----------------- 
                        00001110000110110 
                        00000000000000000 
                        ----------------- 
                         00011100001101100 
                         00000000000000000 
                         ----------------- 
                          00111000011011000 
                          00000000000000000 
                          ----------------- 
                           01110000110110001 
                           00000000000000000 
                           ----------------- 
                            11100001101100010 
                            10001000000100001 
                            ----------------- 
                             11010011010000110 
                             10001000000100001 
                             ----------------- 
                              10110110101001110 
                              10001000000100001 
                              ----------------- 
                               01111101011011110 
                               00000000000000000 
                               ----------------- 
                                11111010110111100 
                                10001000000100001 
                                ----------------- 
                                 11100101100111010 
                                 10001000000100001 
                                 ----------------- 
                                  11011011000110110 
                                  10001000000100001 
                                  ----------------- 
                                   10100110000101110 
                                   10001000000100001 
                                   ----------------- 
                                    01011100000011110 
                                    00000000000000000 
                                    ----------------- 
                                     10111000000111100 
                                     10001000000100001 
                                     ----------------- 
                                      01100000000111010 
                                      00000000000000000 
                                      ----------------- 
                                       11000000001110100 
                                       10001000000100001 
                                       ----------------- 
                                        10010000010101010 
                                        10001000000100001 
                                        ----------------- 
                                         00110000100010110 
                                         00000000000000000 
                                         ----------------- 
                                          01100001000101100 
                                          00000000000000000 
                                          ----------------- 
                                           11000010001011000 
                                           10001000000100001 
                                           ----------------- 
                                            1001010001111001 = CRC 
 

Conversion of the binary value above to hexadecimal by segmenting the bits to nibbles: 
                        binary nibbles   1001 0100 0111 1001 
                        hexadecimal         9    4    7    9

二、CRC的现成算法和工具

当我认为把CRC弄清楚之后,我在网上找它们的现成的实现,发现了不少好东西:

CRC校验hdl代码的生成工具

CRC计算工具

这两用的是同一套算法,我用这套算法计算“A”的16bit-CRC时,发现等于0xB915,而不是上面手算的0x9479!对这些算法进行分析后,发现算法和手算的算法不一样,该算法先将8位数据左移8位,再和预置值异或,然后把得到的值当作一个16位数据用最基本的计算方法计算其CRC。这种算法用C语言表述就是(代码出处):

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. typedef unsigned __int16    INT16U;  
  2. #define CRC_SEED   0xFFFF   // 预置值  
  3. #define POLY16 0x1021  // 该位为简式书写 实际为0x11021  
  4. INT16U wiki_crc(unsigned char c){  
  5.     INT16U rem;  
  6.     INT16U tem;  
  7.     rem=CRC_SEED;  
  8.     tem=(c<<8);   //关键的地方,将数据先左移8位,扩大256倍,  
  9.     rem=rem ^ tem;  //然后与预置值异或,经过这个预处理,之后的计算和手算的没两样  
  10.     for(int j=0;j<8;j++){  
  11.         if(rem & 0x8000){  
  12.             rem=rem<<1;  
  13.             rem=rem ^ POLY16;  
  14.         }  
  15.         else  
  16.             rem=rem<<1;  
  17.     }  
  18.     return rem;  
  19. }  


姑且将这套算法表述为CRC(data,preset),它是跟手算方法有区别的一种CRC计算方法,但是还是能实现CRC的功能。所以我们把它当成正确的算法来使用。

三、算法的多样化

维基百科上对CRC的解释的最后列出了好多种CRC,有CRC16-CCITT,CRC32,CRC16-IBM,等等,这些算法的区别主要是以下几点:

1.预设值的不同,有的是0xFFFF,有的是0x1D0F(这个值下面还会碰到)。

2.一次性处理数据的位宽不同,CRC32,CRC16分别是32位和16位。

3.有的算法将算出来的CRC取反后再附在数据的末尾。比如crc=CRC(data,preset),那么发送的数据是{data,!crc}。

4.校验的判断条件不同,比如CRC("A",0xFFFF)=0xB915,如果发送{"A",0xB915},那么CRC({"A",0xB915},0xFFFF)=0,是符合我们对CRC的原理的理解的,即判断数据是否完整就是看最后的校验值是否为0。如果将CRC取反再发送,则发送{"A",0x46EA},那么CRC({"A",0x46EA},0xFFFF)=0x1D0F,注意这时候判断数据是完整就是看最后的校验值是否等于0x1D0F。


我至今仍然有着疑问,到底0x1D0F是什么数字,哪里都能碰到它,我出于好奇还计算了CRC("A",0x1D0F),结果是0x9479,这就是我们之前看到的手算的结果,好奇怪。。

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

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

相关文章

7.5 GRASP原则五:高内聚 High Cohesion

GRASP原则五&#xff1a;高内聚 High Cohesion   How to keep objects focused, understandable and manageable, and as a side effect support Low Coupling? 如何使对象功能专注、可理解、可管理&#xff0c;同时又支持 低耦合&#xff1f;5.1 GRASP rule 5&#xff1…

资源泄漏:救援的命令模式

多年来&#xff0c; 使用Plumbr进行性能监视时&#xff0c;我遇到了数百个资源泄漏引起的性能问题。 在这篇文章中&#xff0c;我想描述一种最简单的方法来清理资源并避免该问题。 首先&#xff0c;我以电影播放器​​应用程序为例来描述问题。 这种应用程序的主要功能自然是在…

Word文字的三种隐藏方法

在Word的使用过程中&#xff0c;有时候可能需要这么一种情况&#xff1a;一些文字或者段落我们暂时不需要&#xff0c;但又不知后期是否用到&#xff0c;其碍眼却又不能删除。这个时候&#xff0c;最好的方法就是暂时隐藏文字或者段落。今天寻老师教大家三种隐藏Word文本的方法…

Video 对象方法 canPlayType()

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>菜鸟教程(runoob.com)</title> </head> <body> <p>我的浏览器可以播放 MP4 视频吗?<span> <button οnclick"supportType(e…

Linux下区分物理CPU、逻辑CPU和CPU核数

㈠ 概念 ① 物理CPU 实际Server中插槽上的CPU个数 物理cpu数量&#xff0c;可以数不重复的 physical id 有几个 ② 逻辑CPU Linux用户对 /proc/cpu…

java原子更新类_Java内部具有原子更新的动态热交换环境

java原子更新类有人可能会争辩说上述标题可以简称为OSGi &#xff0c;我想在一开始就放弃这种思考过程。 对于OSGi而言&#xff0c;这没有什么冒犯的&#xff0c;它是一个很棒的规范&#xff0c;在实现层或可用性层上都搞砸了&#xff0c;这就是我对OSGi的信念。 当然&#xf…

5个构建Spring Boot API的实用技巧

建筑物身份管理&#xff0c;包括身份验证和授权&#xff1f; 尝试Stormpath&#xff01; 我们的REST API和强大的Java SDK支持可以消除您的安全风险&#xff0c;并且可以在几分钟内实现。 注册 &#xff0c;再也不会建立auth了&#xff01; 每个API开发人员都在寻找一种更安全…

C++项目目录组织结构

项目目录结构的问题基本上是个仁者见仁&#xff0c;智者见智的问题&#xff0c;只要自己用着顺手&#xff0c;使用什么样的目录组织结构是没有什么大碍的。当然如果项目很大&#xff0c;参与的人员很多&#xff0c;那么合理的组织一下目录结构还是会有很大的益处的。不同类型的…

火绒杀毒软件更安静

https://www.huorong.cn/转载于:https://www.cnblogs.com/Tom-yi/p/10554564.html

完全编译安装boost

文章目录 1. 安装依赖2. 编译安装 boost3. 环境变量配置 boost是C世界中相当优秀的第三方库&#xff0c;被选入STL的也有不少&#xff0c;其中用到的C奇技淫巧更是数不胜数。 安装依赖 boost 在类 Unix 系统上的安装&#xff0c;可以参考官方文档的 Get Started&#xff0c;除此…

c#Md5 32位加密结果少了两个0的原因

我们的&#xff1a; e1adc3949ba59abbe56e57f20f883e 第三方的&#xff1a;e10adc3949ba59abbe56e057f20f883e 原因: 这个是很常见的错误&#xff0c;你字节转换成字符串的时候要保证是2位宽度啊&#xff0c;某个字节为0转换成字符串的时候必须是00的&#xff0c;否则就会丢失…

lambdas for_Wordcounter,使用Lambdas和Fork / Join计算Java中的单词数

lambdas for这些天来&#xff0c;我发布了Wordcounter &#xff0c;这是一个Java库和命令行实用程序&#xff0c;用于对文本文件中的单词进行计数并对单词计数进行分析&#xff0c;从而大量使用了功能编程结构和并行计算方法。 这是我在“令人讨厌的快速问答”大赛第四个条目SA…

Bitmap Font生成

工具&#xff1a;AngelCode 的 Bitmap Font Generator。把需要用到的文字写到一个txt&#xff0c;注意编码为Unicode。接着&#xff0c;在工具里 Edit->select chars from file选择刚才新建的txt文件。然后。。。之后的没啥细节&#xff0c;随意搞吧。转载于:https://www.cn…

分隔和截断字符串, boost string algorithm library中的split和trim

http://www.boost.org/doc/libs/1_46_1/doc/html/string_algo.html 这个库是个 headers only library  这个库提供了STL没有提供的 string-related算法, 但是实现做到了可以用在任何 character 的 container上 split 在写在线状态的改造时候要把一个字符串中描述的几种类型拆…

使用Spring Integration重试RabbitMQ

我最近阅读了有关使用RabbitMQ重试的方法 在这里&#xff0c;并想尝试类似的方法 Spring Integration &#xff0c;提供了一组很棒的集成抽象。 TL; DR解决的问题是重试一次消息&#xff08;在处理失败的情况下&#xff09;&#xff0c;两次重试之间有较大的延迟&#xff08…

Vue_(Router路由)-vue-router路由的基本用法

vue-router官网&#xff1a;传送门 vue-router起步&#xff1a;传送门 vue-router路由&#xff1a;Vue.js官网推出的路由管理器&#xff0c;方便的构建单页应用 单页应用&#xff1a;Single Page Application简称SPA&#xff0c;只有一个web页面的应用&#xff0c;用户与应用交…

利用boost做string到wstring转换,以及字符集转换

#include <boost/locale.hpp> int _tmain(int argc, _TCHAR* argv[]) {//std::locale::global(std::locale("utf-8"));std::locale::global(std::locale("")); // 设置全局的C运行库locale 可以针对cout fstream等单独设置 空表示默认使用当前系统…

P4198 楼房重建

[Luogu4198] 原题解 19.3.21 用线段树维护有关单调栈的问题 不要pushdown , 但是pushup的时候需要特别注意. 19.3.31 这里的\(pushup2\)其实就是几个特判 : 没有 , 直接返回当前区间答案 , 区间长度为\(1\) , 以及剩下两大类 , 这里有一个模板 : if(mx[ls]<tmp) return push…

Linux多线程实践(1) --线程理论

线程概念 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列/指令序列”; 一切进程至少有一个执行线程; 进程 VS. 线程 1.进程是资源分配(进程需要参与资源的竞争)的基本单位,而线程是处理器调…

蓝桥杯 密文搜索(全排列)

题目描述福尔摩斯从X星收到一份资料&#xff0c;全部是小写字母组成。他的助手提供了另一份资料&#xff1a;许多长度为8的密码列表。福尔摩斯发现&#xff0c;这些密码是被打乱后隐藏在先前那份资料中的。请你编写一个程序&#xff0c;从第一份资料中搜索可能隐藏密码的位置。…