1. 程式人生 > >CRC32校驗演算法C語言版(查表法)

CRC32校驗演算法C語言版(查表法)

最近用到CRC校驗演算法,就找了些資料,學習了一下,網上關於CRC32的資料也多,但感覺不是很完整,或者太高深。

CRC演算法查表法很常見,但表是怎麼來的,有些資料說得不很清楚。

我來說一下我的看法:

1.CRC校驗變化太多,有CRC4/5/6/7/8/16/32,每一種的多項式也有很多種變化,並不是一成不變的;

2.輸入輸出方式也有區別,有一些初始值是0,有一些初始值是0xFFFFFFFF,有一些直接返回,有一些異或返回。

因此,CRC校驗很難用一個程式碼相容全部,只能根據專案需要修改相關引數了。

計算方法:

1.先要知道多項式是什麼樣子,以這個IEEE802.3標準CRC32多項式為例:x32 + x26

 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x+ 1

2.轉換成一個值(這個值的命名我不知道啊)

  x32  則對應32bit = 1, x26 則對應26bit=1,得出一個值:(1<<32)|(1<<26)|(1<<23)|(1<<22)|...|(1<<1)|(1)=0x104C11DB7,對於CRC32取低32位,則=0x4C11DB7

3.用這個值通過一定方法生成長度為256的碼錶,對於CRC32表內每個元素都為32bit.

4.用一定的方法查表得出CRC32值。

好了,可以貼程式碼了:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>


static uint32_t table[256];


//位逆轉
static uint32_t bitrev(uint32_t input, int bw)
{
    int i;
    uint32_t var;
    var = 0;
    for(i=0; i<bw; i++)
    {
        if(input & 0x01)
        {
            var |= 1<<(bw - 1 - i);
        }
        input >>= 1;
    }
    return var;
}


//碼錶生成
void crc32_init(uint32_t poly)
{
    int i;
    int j;
    uint32_t c;


    poly = bitrev(poly, 32);
    for(i=0; i<256; i++)
    {
        c = i;
        for (j=0; j<8; j++)
        {
            c = (c & 1) ? (poly ^ (c >> 1)) : (c >> 1);
        }
        table[i] = c;
    }
}


//計算CRC
uint32_t crc32(uint32_t crc, void* input, int len)
{
    int i;
    uint8_t index;
    uint8_t *p;
    p = (uint8_t*)input;
    for(i=0; i<len; i++)
    {
        index = (*p ^ crc);
        crc = (crc >> 8) ^ table[index];
        p++;
    }
    return crc;
}


//測試用例
void main(void)
{
    uint32_t crc;
    crc32_init(0x4C11DB7);
    crc = crc32(0xFFFFFFFF, "1234567890", 10);
    printf("CRC32 = 0x%08X\n", crc ^ 0xFFFFFFFF);
    system("pause");
}

2017.11.07更新程式碼: 由於原始碼使用unsigned long型別,在64位環境下是64位資料型別,會出現計算結果不正確,因此將其替換為uint32_t型別;

計算結果:

CRC32=0x261DAEE5