1. 程式人生 > >crc32 演算法與實現

crc32 演算法與實現

crc就是一個數值,該數值用於檢驗資料的正確性,crc校驗的原理就是將需要作校驗的資料與一個數據模2相除,得到的餘數即為校驗值。

      模2相除就是在除的過程中用模2加,模2加實際上就是異或運算,就是不進行進位操作,即相同為假,不相同為真。

下面是幾種CRC校驗的生成多項式:

CRC8 = X8+X5+X4+1

CRC-CCITT = X16+X12+X5+1

CRC16=X16+X15+X2+1

CRC12=X12+X11+X3+X2+1

CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X+1

一個多項式就是一個位元流,也就是由0、1組合起來的一組數

我們需要獲取的常數就是上面多項式所對應的反轉多項式(反轉多項式:在資料通訊時,資訊位元組先傳送或接受低位位元組,如重新排列則影響速度)。

下面使用查表法實現crc校驗,具體步驟如下:

(1)將上次計算出的CRC校驗碼右移一個位元組;
(2)將移出的這個位元組與新的要校驗的位元組進行XOR 運算;
(3)用運算出的值在預先生成碼錶中進行索引,獲取對應的值(稱為餘式);
(4)用獲取的值與第(1)步右移後的值進行XOR 運算;
(5)如果要校驗的資料已經處理完,則第(4)步的結果就是最終的CRC校驗碼。如果還有資料要進行處理,則再轉到第(1)步執行。

本例使用crc32校驗,使用上面crc32的生成多項式,值為0xEDB88320

首先寫一個功能函式,實現生成一個crc表,然後寫一個功能函式,用於計算crc值,最後再寫一個函式用於比較crc值,下面是全部程式碼:

  1. #include
  2. #include
  3. #include
  4. #include
  5. uint32_t crc32_table[256];  
  6. int make_crc32_table()  
  7. {  
  8.     uint32_t c;  
  9.     int i = 0;  
  10.     int bit = 0;  
  11.     for(i = 0; i < 256; i++)  
  12.     {  
  13.         c  = (uint32_t)i;  
  14.         for(bit = 0; bit < 8; bit++)  
  15.         {  
  16.             if(c&1)  
  17.             {  
  18.                 c = (c >> 1)^(0xEDB88320);  
  19.             }  
  20.             else
  21.             {  
  22.                 c =  c >> 1;  
  23.             }  
  24.         }  
  25.         crc32_table[i] = c;  
  26.     }  
  27. }  
  28. uint32_t make_crc(uint32_t crc, unsigned char *string, uint32_t size)  
  29. {  
  30.     while(size--)  
  31.         crc = (crc >> 8)^(crc32_table[(crc ^ *string++)&0xff]);  
  32.     return crc;  
  33. }  
  34. void compare_crc(char *filename)  
  35. {  
  36.     FILE *sp = NULL;  
  37.     uint32_t srcCrc ;  
  38.     uint32_t calcuCrc = 0xffffffff;  
  39.     unsigned char buf[1024];  
  40.     uint32_t count;  
  41.     if(filename == NULL)  
  42.     {  
  43.         printf("filename is null\n");  
  44.         exit(1);  
  45.     }  
  46.     sp = fopen(filename, "rb");  
  47.     if(sp == NULL)  
  48.     {  
  49.         printf("open file fail\n");  
  50.         exit(1);  
  51.     }  
  52.     fread(&srcCrc, 1, 4, sp);  
  53.     printf("In %s: src crc is 0x%x\n", __FUNCTION__, srcCrc);     
  54.         if(sp)  
  55.         {  
  56.                 while(!feof(sp))  
  57.                 {  
  58.                         memset(buf, 0, sizeof(buf));  
  59.                         count = fread(buf, 1, sizeof(buf), sp);  
  60.                         calcuCrc = make_crc(calcuCrc, buf, count);  
  61.                 }  
  62.         }  
  63.     printf("In %s: calcuCrc is 0x%x\n", __FUNCTION__, calcuCrc);  
  64.     fclose(sp);  
  65.     if(srcCrc == calcuCrc)  
  66.     {  
  67.         printf("In %s: the calculate crc equal the src crc in file \n", __FUNCTION__);  
  68.     }  
  69.     else
  70.     {  
  71.         printf("In %s: the calculate crc not equal the src crc in file \n", __FUNCTION__);  
  72.     }  
  73. }  
  74. int main()  
  75. {  
  76.     int i;  
  77.     FILE *sp = NULL;  
  78.     FILE *dp = NULL;  
  79.     uint32_t count;  
  80.     uint32_t crc = 0xFFFFFFFF;  
  81.     unsigned char buf[1024];  
  82.     make_crc32_table();  
  83.     sp = fopen("/home/user/work_soft/crc_check/bak/test.txt""rb");  
  84.     if(sp == NULL)  
  85.     {  
  86.         printf("open file error\n");  
  87.         return -1;  
  88.     }  
  89.     dp = fopen("/home/user/work_soft/crc_check/bak/testcrc.txt""wb");  
  90.     if(dp == NULL)  
  91.     {  
  92.         printf("open file error\n");  
  93.         return -1;  
  94.     }  
  95.     if(sp)  
  96.     {  
  97.         while(!feof(sp))  
  98.         {  
  99.             memset(buf, 0, sizeof(buf));  
  100.             count = fread(buf, 1, sizeof(buf), sp);  
  101.             crc = make_crc(crc, buf, count);          
  102.         }  
  103.     }  
  104.     printf("In main: calculate crc is 0x%x\n", crc);  
  105.     if(dp)  
  106.     {  
  107.         fwrite(&crc, 1, 4, dp);//write the crc into the file testcrc.txt
  108.         fseek(sp, 0, SEEK_SET);  
  109.         while(!feof(sp))  
  110.         {  
  111.             memset(buf, 0, sizeof(buf));  
  112.                         count = fread(buf, 1, sizeof(buf), sp);  
  113.             fwrite(buf, 1, count, dp);  
  114.         }  
  115.         fclose(sp);  
  116.         fclose(dp);  
  117.     }  
  118.     compare_crc("/home/user/work_soft/crc_check/bak/testcrc.txt");  
  119.     return 0;  
  120. }  
上面程式碼是根據查表法實現的,首先生成crc表,make_crc32_table就是根據crc校驗的原理實現的,對0-255進行模2除法生成crc表;

函式make_crc是根據查表法的步驟實現的;而函式compare_crc則用來開啟一個在頭部嵌入crc值的檔案,首先將檔案頭部的crc值取出(若用於功能實現,可設計一個數據結構用於存放crc等相關值,並存放在檔案的頭部),然後再讀取檔案的餘下內容進行

crc計算,將計算出的crc值與從檔案中讀出的crc值進行比較,若相等則說明檔案內容沒有出錯。下面是執行結果:


如果要將crc嵌入到檔案頭部,比如將計算得出的crc嵌入到升級檔案的頭部,由於我們生成的crc值的儲存方式可能會因為不同的主機而不同(大端或小端)

所以在將crc值嵌入到升級檔案的頭部時,最好再加一個位元組用於說明crc值得儲存方式是大端還是小端模式,這樣接收方就可以選擇同一個儲存方式,來確定讀取的crc值是正確的