CRC校验算法的解析,暨对网上的CRC详解的补充
来源:互联网 发布:gif动态制作软件 编辑:程序博客网 时间:2024/06/06 02:58
一、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
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语言表述就是(代码出处):
姑且将这套算法表述为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,这就是我们之前看到的手算的结果,好奇怪。。
- CRC校验算法的解析,暨对网上的CRC详解的补充
- CRC校验算法的解析,暨对网上的CRC详解的补充
- CRC校验的算法
- 查表法的crc校验算法
- CRC校验的实现
- CRC的校验原理
- CRC的校验原理
- CRC的校验原理
- CRC的校验原理
- CRC的校验原理
- 通俗易懂的CRC校验
- CRC校验的实施
- CRC的校验原理
- CRC校验的解读
- 关于CRC校验的代码
- 一种CRC校验的方法
- CRC校验码的校验方法
- crc校验的实现(移位寄存器)
- Git管理
- MyEclipse 2016 Stable 1.0破解教程
- 通过项目逐步深入了解Mybatis<一>
- javafx textfied 属性改变事件与回车触发事件
- nginx配置反向代理示例
- CRC校验算法的解析,暨对网上的CRC详解的补充
- Spring 7大功能模块的作用
- Mysql库表数据随时从生产拉取到数仓(Mysql)的方案(3)
- spring的form提交以及JSTL
- Android练手小项目:仿看房app
- Okhttp3表单上传数据到服务器使用指南
- sicily Highways prim算法与kruskal算法详解
- Mac 运行sh文件,也就是传说中的shell脚本
- Java经典兔子问题