解讀一段循環冗餘校驗(CRC)算法程序

今天遇到一段這樣的程序,一時半會很難讀懂:

alt_u32 crc32_bit(alt_u8 *ptr, alt_u32 len, alt_u32 gx)
{
    alt_u8 i;
    alt_u32 crc = 0xffffffff;
    while (len--)
    {
        for (i = 1; i != 0; i <<= 1)
        {
            if ((crc & 0x80000000) != 0)
            {
                crc <<= 1;
                crc ^= gx;
            }
            else
                crc <<= 1;
            if ((*ptr & i) != 0)
                crc ^= gx;
        }
        ptr++;
    }
    return (Reflect(crc, 32) ^ 0xffffffff);
}

這是一個計算循環冗餘校驗碼的算法,CRC的作用是通過校驗對數據的正確性進行檢查。這個程序的寫法讓人費解,下面一句句進行思考解讀。
已知傳進的指針ptr指向一個數據數組,len爲其長度,gx爲校驗多項式,是8位數據。
外層的循環是len次,每次len減一,ptr增一,因此每次ptr指向一個8位數據。
內層循環是8次,剛好對應數據的8位。

在循環內部:因爲有兩個條件語句,根據不同條件和結果列如下:
crc & 0x80000000 == 0,*ptr & i == 0 :crc<<=1
crc & 0x80000000 == 0,*ptr & i == 1 :crc<<=1;crc^=gx
crc & 0x80000000 == 1,*ptr & i == 0 :crc<<=1;crc^=gx
crc & 0x80000000 == 1,*ptr & i == 1 :crc<<=1
注意第四種情況中,crc先異或後又再次異或 等於沒有做任何操作。

其中,crc & 0x80000000是判斷crc的最高位(記作條件A),*ptr & i是判斷第i位(記作條件B)。之後的操作是將crc左移(記作操作C),以及crc左移後與gx異或(記作操作D)。
從以上判斷可以得出條件-結果對:
A==B-> C
A != B -> D
當兩者相同時執行C操作,不相同時執行D操作。C、D操作唯一區別是是否與gx進行異或,因此可以將唯一不同的操作歸納:將操作C視爲值0,D視爲1。即是說:操作值等於A^B。也就是當數據第i位與crc最高位的相異時執行操作:crc^=gx。
解讀到此處,已然明瞭。

crc變量在此處代表前一次計算的結果,初始爲全1。將其最高位與數據最第i位相比,不同則將其進行與gx的異或。
第一次異或:0xffff與gx,將會得到~gx<<1(gx全反位左移)
第二次異或:~gx<< x+1 與 gx,x代表最近一次不滿足A^B的條件的位數
……
在草稿紙上進行演算,發現這就是模二除法,最後得到的crc就是餘數。但是要注意,這裏的 i 是從數據的低位開始計算的,而crc是從高位起。也就是說,每一個數據都是反着算的(這與機器大小端無關),因此在最後需要將其位全部反過來(Reflect函數)才能用於校驗。

其中的具體原理還沒有弄清楚,但是解讀的思路給了一些其他的啓發。另外,這裏查到了一篇CRC算法詳解,其思路比較清晰:
http://blog.csdn.net/liyuanbhu/article/details/7882789

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章