分享

C语言获取文件CRC32算法附加CRC原理

 WUCANADA 2014-02-25

搞弄了半天,终于把CRC的原理大致明白了,其实质上就是先确定一个多项式作为CRC标准,然后将二进制序列左移对应的位数再除以这个多项式,最后得到的余数就是CRC码。下面是网上找到的CRC原理,不弄长的了,凑合看吧。

CRC 校验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的监督码(既CRC 码)r 位,并附在信息后边,构成一个新的二进制码序列数共(k+r)位,最后发送出去。在接收端,则根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。

16 位的CRC 码产生的规则是先将要发送的二进制序列数左移16 位(既乘以2的16次方)后,再除以一个多项式,最后所得到的余数既是CRC 码。

求CRC码所采用的模2加减运算法则,即是不带进位和借位的按位加减,这种加减运算实际上就是逻辑上的异或运算,加法和减法等价,乘法和除法运算与普通代数式的乘除法运算是一样,符合同样的规律。
生成CRC码的多项式如下,其中CRC-16 和CRC-CCITT产生16 位的CRC码,而CRC-32 则产生的是32 位的CRC码,不同的标准计算出来的CRC值不同。

CRC-16:(美国二进制同步系统中采用) G(X ) = X16 + X15 + X2 +1
CRC-CCITT:(由欧洲CCITT 推荐) G(X ) = X16 + X12 + X5 +1
CRC-32: G(X ) = X32 + X26 + X23 + X22 + X16 + X12 + X11 + X10 + X8+ X7 + X5 + X4 + X2 + X1 +1

接收方将接收到的二进制序列数(包括信息码和CRC 码)除以多项式,如果余数为0,则说明传输中无错误发生,否则说明传输有误,关于其原理这里不再多述。用软件计算CRC 码时,接收方可以将接收到的信息码求CRC 码,比较结果和接收到的CRC 码是否相同。注意发送方和接受方的CRC标准要保持一致,选择什么标准依实际情况而定。

下面是经常用到的获取文件CRC32值的算法,与WINRAR中的CRC值一致,非常实用啊,值得收藏。

#include <stdio.h>
#include <inttypes.h>
 
#define Poly 0xEDB88320L	//CRC32标准
static uint32_t crc_tab32[256];	//CRC查询表
 
static void init_crc32_tab(void);	//生成CRC查询表
uint32_t get_crc32(uint32_t crcinit, uint8_t * bs, uint32_t bssize);	//获得CRC
uint32_t GetFileCRC(FILE *fd);	//获得文件CRC
 
static void init_crc32_tab( void ) 
{
	int i, j;
	uint32_t crc;
 
	for (i=0; i<256; i++)
	{
		crc = (unsigned long)i;
		for (j=0; j<8; j++) 
		{
			if ( crc & 0x00000001L )
				crc = ( crc >> 1 ) ^ Poly;
			else      
				crc = crc >> 1;
		}
		crc_tab32[i] = crc;
	}
}
 
uint32_t get_crc32(uint32_t crcinit, uint8_t * bs, uint32_t bssize)
{
	uint32_t crc = crcinit^0xffffffff;
 
	init_crc32_tab();
	while(bssize--)
		crc=(crc >> 8)^crc_tab32[(crc & 0xff) ^ *bs++];
 
	return crc ^ 0xffffffff;
}
 
uint32_t GetFileCRC(FILE *fd)
{
	uint32_t size = 16 * 1024;
	uint8_t crcbuf[size];
	uint32_t rdlen;
	uint32_t crc = 0;	//CRC初始值为0
 
	while((rdlen = fread(crcbuf, sizeof(uint8_t), size, fd)) > 0)
		crc = get_crc32(crc, crcbuf, rdlen);
 
	return crc;
}
 
int main(int argc,char **argv)
{
	FILE *fd;
	unsigned int value=0;
 
	if(argc<2)
	{
		printf("Usage: %s file",basename(argv[0]));
		exit(1);
	}
	if((fd=fopen(argv[1],"r"))==NULL)	
	{
		perror("Error:");
		exit(1);
	}
	value = GetFileCRC(fd);
	printf("CRC: %X\n",value);
 
	fclose(fd);
	return 0;
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多