生活随笔
收集整理的這篇文章主要介紹了
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 )?1111111111111111 01000001 0000000000000000 ? ??????????????????? 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
typedef ?unsigned? __int16 ????INT16U;?? #define?CRC_SEED???0xFFFF???//?預置值 ?? #define?POLY16?0x1021??//?該位為簡式書寫?實際為0x11021 ?? INT16U?wiki_crc(unsigned?char ?c){?? ????INT16U?rem;?? ????INT16U?tem;?? ????rem=CRC_SEED;?? ????tem=(c<<8);????? ????rem=rem?^?tem;???? ????for ( int ?j=0;j<8;j++){?? ????????if (rem?&?0x8000){?? ????????????rem=rem<<1;?? ????????????rem=rem?^?POLY16;?? ????????}?? ????????else ?? ????????????rem=rem<<1;?? ????}?? ????return ?rem;?? }??
姑且將這套算法表述為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详解的补充 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。