日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/2 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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
  • 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);???//關鍵的地方,將數據先左移8位,擴大256倍,??
  • ????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详解的补充的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。