最近用到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