开发环境:VC6++,可以移植到其他环境
关于CRC效验原理可以参考博客https://blog.youkuaiyun.com/zjli321/article/details/52998468
CRC效验通常有两种方法,一种是模2除法,另一种是查表法(这种表也只先通过模2除法算好,然后调用)
/************************************************************************************************************************************/
#include<stdio.h>
/****用于填写CRC类型的的枚举选项****/
enum CrcInversionOption
{
CrcInversionFalse=0,
CrcInversionTure
};
/*******************************************************************************************/
/*Local Macro and Tyedef */
/*******************************************************************************************/
typedef struct _Crc16Mode_Type
{
unsigned short Polynom;
unsigned short Seed;
unsigned char IsDataInInversion; //填enum类型是否反序
unsigned char IsDataOutInversion; //填enum类型是否反序
unsigned short ResultXorData;
} Crc16Mode_Type;
typedef struct _Crc32Mode_Type
{
unsigned long Polynom;
unsigned long Seed;
unsigned char IsDataInInversion; //填enum类型是否反序
unsigned char IsDataOutInversion; //填enum类型是否反序
unsigned long ResultXorData;
} Crc32Mode_Type;
/***************************************************************************************************
*时间:2019/05/30
*函数作用:求数据的按位反转
*函数名:unsigned long bitrev(unsigned long input, int bw)
*形参内容:待输入的按位反转 unsigned long input 待输入的按位反转的长度 int bw
*
*返回值: 反转之后的值 var
******************************************************************************************************/
static unsigned long bitrev(unsigned long input, int bw)
{
int i;
unsigned long var;
var = 0;
for(i=0;i<bw;i++)
{
if(input & 0x01)
{
var |= 1<<(bw-1-i);
}
input>>=1;
}
return var;
}
/*************************************************************************************************************
*时间:2019/06/01
*函数作用:求32位CRC的效验码、支持CRC32和CRC_MPEG_2的两种类型
*函数名:unsigned long Crc32_GetCrc(Crc32Mode_Type CrcMode, unsigned int *DataAddrStart, unsigned long Length)
*形参内容:CrcMode CRC32类型参数 *DataAddrStart 要效验的数据首地址 Length要效验的数据长度
*反序多相式简写:
*返回值: 运算后的CRC效验码
***************************************************************************************************************/
unsigned long Crc32_GetCrc(Crc32Mode_Type CrcMode, unsigned char *DataAddrStart, unsigned long Length)
{
unsigned int i,j = 0;
unsigned char *data=DataAddrStart;
unsigned long crc =CrcMode.Seed;
if(CrcInversionFalse==CrcMode.IsDataInInversion)
{
while ((Length--) != 0)
{
crc ^= (unsigned long)data[j] << 24;
j++;
for (i = 0; i < 8; ++i)
{
if ((crc & 0x80000000) != 0)
{
crc = (crc << 1) ^ CrcMode.Polynom; //0x04C11DB7
}
else
{
crc <<= 1;
}
}
}
}
if(CrcInversionTure==CrcMode.IsDataInInversion)
{
CrcMode.Polynom=bitrev(CrcMode.Polynom,32); //因为上面输入反序算法有问题,所以当使用到输入反序的时候调用下面
while((Length--)!=0)
{
crc ^= (unsigned int)data[j];
j++;
for (i=0; i<8; i++) //右移,相当于反转数据,同时也需要反转POLY
{
if(crc&1)
{
crc=CrcMode.Polynom^(crc>>1);
}
else
{
crc=crc>>1;
}
}
}
if(CrcInversionTure==CrcMode.IsDataOutInversion) //判断数据输出是否需要反转 //输出反转,相当于算法的不翻转,与下面的反转抵消。
{crc=bitrev(crc,32);}
}
if(CrcInversionTure==CrcMode.IsDataOutInversion) //判断数据输出是否需要反转
{crc=bitrev(crc,32);}
return crc^=CrcMode.ResultXorData;
}
/*************************************************************************************************************
*时间:2019/05/31
*函数作用:求16位CRC的效验码、支持CRC16 IBM、MAXIM、USB、MODBUS、CCITT、CCITT-FALSE、X25、XMODEM和DNP九种模式
*函数名:unsigned long Crc32_GetCrc(Crc32Mode_Type CrcMode, unsigned int *DataAddrStart, unsigned long Length)
*形参内容:CrcMode CRC16类型参数 *DataAddrStart 要效验的数据首地址 Length要效验的数据长度
*反序多相式简写:
*返回值: 运算后的CRC效验码
***************************************************************************************************************/
unsigned short Crc16_GetCrc(Crc16Mode_Type CrcMode, unsigned char *DataAddrStart, unsigned long Length)
{
unsigned char *data=DataAddrStart; //数据首地址
unsigned short wCRCin = CrcMode.Seed;
unsigned short wCPoly = CrcMode.Polynom;
unsigned char wChar = 0;
int i;
while (Length--)
{
wChar = *(DataAddrStart++);
if(CrcInversionTure==CrcMode.IsDataInInversion)
{wChar=(unsigned char)bitrev(wChar,8);}
wCRCin ^= (wChar << 8);
for(i = 0; i < 8; i++)
{
if(wCRCin & 0x8000)
{
wCRCin = (wCRCin << 1) ^ wCPoly;
}
else
{
wCRCin = wCRCin << 1;
}
}
}
if(CrcInversionTure==CrcMode.IsDataInInversion)
{wCRCin=(unsigned short)bitrev(wCRCin,16);}
return wCRCin^=CrcMode.ResultXorData;
}
/***供函数验证使用****/
void main()
{
unsigned char id[]={0x12,0x34,0x56,0x78,0x90};
unsigned long Crc=0;
unsigned long CrcS=0;
Crc32Mode_Type Crc32Inversion;
Crc16Mode_Type Crc16Inversion;
/*****需要调用的CRX32效验多项式、初始值、反序、输出异或值配置******************************************* /
Crc32Inversion.Polynom=0x04C11DB7;
Crc32Inversion.Seed=0x00000000;
Crc32Inversion.IsDataInInversion=CrcInversionFalse;
Crc32Inversion.IsDataOutInversion=CrcInversionTure;
Crc32Inversion.ResultXorData=0x00000000;
/***************************************************************************************************** /
CrcS=Crc32_GetCrc(Crc32Inversion,id,sizeof(id));
printf("Crcs=%08X\n",CrcS);
CrcS=Crc32_GetCrc(Crc32Inversion,id,sizeof(id));
printf("Crcs=%08X\n",CrcS);
/*****需要调用的CRX16效验多项式、初始值、反序、输出异或值配置*********************************************** / Crc16Inversion.Seed=0xFFFF;
Crc16Inversion.Polynom=0x1021;
Crc16Inversion.IsDataInInversion=CrcInversionTure;
Crc16Inversion.IsDataOutInversion=CrcInversionTure;
Crc16Inversion.ResultXorData=0xFFFF;
/***************************************************************************************************** /
Crc=Crc16_GetCrc(Crc16Inversion,id,sizeof(id));
printf("Crcv=0x%04X\n",Crc);
Crc=Crc16_GetCrc(Crc16Inversion,id,sizeof(id));
printf("Crcv=0x%04X\n",Crc);
return;
}
编译输出结果