易语言教程_易语言源码_易语言视频教程_易语言论坛

 找回密码
 点击注册

Vip新手入门区
新手学习指南  学员作品展示 Vip课程总纲  Vip绝密课程系列

Vip相关下载区
Vip模块下载   Vip模块绑定   Vip模块例子 魔鬼插件下载  魔鬼插件例子  教程工具下载

Vip论坛服务区
教程问题提问区   模块问题提问区 技术交流区   魔鬼插件建议   忘记密码找回

VIP会员办理QQ: 8643245   
【请先加好友,然后到好友列表双击联系客服,办理VIP会员。】
【基础篇】易语言辅助入门基础教程
VIP模块办理QQ: 7189694 办理正版魔鬼作坊VIP模块 【基础篇】OD与CE入门基础教程
办理【终身VIP会员】“秒杀价” 仅需 RMB278.00元… 【基础篇】零基础绝密汇编语言入门课程 (共26课已完成)…
办理VIP详情…猛击这里查看详情 【基础篇】VIP辅助入门基础教程-新手必学 已发布10课 ……
VIP教程免费试看章节…猛击下载 【第1款】制作“辅助挂”教程目录查看(共107+16_x64下更新课已完成)…
亲爱的VIP学员,请到此写下你学习的感受与发布作品截图… 【第2款】制作“任务挂”教程目录查看(共77+1_x64下更新课已完成)…
卍解吧!不用bp send类封包断点找CALL的各种通杀思路 【第3款】驱动过保护技术课程(共38课已完成)…
【绝密教程】VIP绝密教程系列---注意:随时会更新! 【第4款】VIP邪恶二叉树辅助课程 (共31+17_x64下更新课已完成)…
【精品第13款】3D射击游戏与页游透视 智辅课程 已完成17课… 【第5款】零基础易语言按键辅助教程 (30课已完成)…
【精品第14款】变态功能辅助是如何炼成的 已完成36课… 【第6款】从零开始学习封包辅助技术教程(20课已完成) …
【精品第15款】DNF商业变态辅助的修炼之路 已完成27课… 【第7款】大杀特杀分析来源与CALL吸血鬼课程 (56课已完成)
【精品第16款】中控台多线程多开自动化商业辅助课程 已完成66课… 【第8款】完全零基础网页辅助课程(40课已完成)
【全新精品第17款】检测原理与过游戏内存检测技术课程 已发布9课… 【第9款】自动登录与操控LUA技术课程 (共46+8_x64下更新课已完成)…
【全新精品第18款】手游全自动化任务脚本辅助课程 已发布25课…… 【第10款】网页辅助封包脱机进阶课程 已完成30课…
【全新精品第19款】D3D方框骨骼透视与自瞄辅助课程进阶篇 已发布34课…… 【第11款】VC++ Lua脚本辅助课程 已完成112课…
【全新精品第20款】 X64模拟器吃鸡游戏方框透视自瞄辅助课程 发布中... 【第12款】网游脱机封包智辅课程 已完成35课…
查看: 1688|回复: 0

CRC校验方法,用C语言实现源代码

[复制链接]

20

主题

3

回帖

32

积分

编程入门

Rank: 1

魔鬼币
573
发表于 2017-5-27 13:29:47 | 显示全部楼层 |阅读模式
CRC(Cyclic Redundancy Check)校验应用较为广泛,以前为了处理简单,在程序中大多数采用LRC(Longitudinal Redundancy Check)校验,LRC校验很好理解,编程实现简单。用了一天时间研究了CRC的C语言实现,理解和掌握了基本原理和C语言编程。结合自己的理解简单写下来。

1、CRC简介

CRC检验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个检验码r位(就是CRC码),附在信息后面,构成一个新的二进制码序列数共(k+r)位,最后发送出去。接收端根据同样的规则校验,以确定传送中是否出错。接收端有两种处理方式:1、计算k位序列的CRC码,与接收到的CRC比较,一致则接收正确。2、计算整个k+r位的CRC码,若为0,则接收正确。

CRC码有多种检验位数,8位、16位、32位等,原理相同。16位的CRC码产生的规则是先将要发送的二进制序列数左移16位(即乘以2的16次方后),除以一个多项式,最后所得到的余数就是CRC码。

求CRC码所采用的是模2运算法则,即多项式除法中采用不带借位的减法运算,运算等同于异或运算。这一点要仔细理解,是编程的基础。

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

2、按位计算CRC

采用CRC-CCITT多项式,多项式为0x11021,C语言编程时,参与计算为0x1021,这个地方得深入思考才能体会其中的奥妙,分享一下我的思路:当按位计算CRC时,例如计算二进制序列为1001 1010 1010 1111时,将二进制序列数左移16位,即为1001 1010 1010 1111 (0000 0000 0000 0000),实际上该二进制序列可拆分为1000 0000 0000 0000 (0000 0000 0000 0000) + 000 0000 0000 0000 (0000 0000 0000 0000) + 00 0000 0000 0000 (0000 0000 0000 0000) + 1 0000 0000 0000 (0000 0000 0000 0000) + ……

现在开始分析运算:

<1>对第一个二进制分序列求余数,竖式除法即为0x10000 ^ 0x11021运算,后面的0位保留;

<2>接着对第二个二进制分序列求余数,将第一步运算的余数*2后再和第二个二进制分序列一起对0x11021求余,这一步理解应该没什么问题。如果该分序列为0,无需计算。

<3>对其余的二进制序列求余与上面两步相同。

<4>计算到最后一位时即为整个二进制序列的余数,即为CRC校验码。

该计算方法相当于对每一位计算,运算过程很容易理解,所占内存少,缺点是一位一位计算比较耗时。

下面给出C语言实现方法:

复制代码 代码如下:

unsigned char test[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};

unsigned char len = 16;

void main( void )

{

unsigned long t

emp = 0;

unsigned int crc;

unsigned char i;

unsigned char *ptr = test;

while( len-- ) {

for(i = 0x80; i != 0; i = i >> 1) {

temp = temp * 2;

if((temp & 0x10000) != 0)

temp = temp ^ 0x11021;

if((*ptr & i) != 0)

temp = temp ^ (0x10000 ^ 0x11021);

}

ptr++;

}

crc = temp;

printf("0x%x ",crc);

}

上面的程序根据运算分析而来,很容易理解。为了节约内存空间,我们对程序作进一步的简化。分析可知,当二进制序列中上一位计算的余数第15bit位为1时,即( 上一位计算的余数 & 0x8000) != 0,计算本位时,上一位余数 * 2后可对0x11021作求余运算,然后再加上本位计算所得余数。这个很好理解,也就是说,打个比方,把它看作简单的除法,计算上一位时的余数乘以2后,如果比较大可以当被除数,就再去除除数求余。有一点和普通除法不同的是,因为多项式除法中采用不带借位的减法运算,所以0x10000也可以被0x11021除,余数并非为0x10000,而是0x1021。这个自己动手算一下就知道了。余数之和也是不带进位的加法运算,即异或。最后还强调一点,因为二进制序列是左移16位后参与运算的,所以,一直算到序列的最后一位也是可以被除的,这点大家要明白。下面给出简化后的C语言实现。

复制代码 代码如下:

unsigned char test[16] ={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};

unsigned char len = 16;

void main( void )

{

unsigned int crc = 0;

unsigned char i;

unsigned char *ptr = test;

while( len-- ) {

for(i = 0x80; i != 0; i = i >> 1) {

if((crc & 0x8000) != 0) {

crc = crc << 1;

crc = crc ^ 0x1021;

}

else {

crc = crc << 1;

}

if((*ptr & i) != 0) {

crc = crc ^ 0x1021;

}

}

ptr++;

}

printf("0x%x ",crc);

}

上面这段程序网上较为常见,但冇得详细的解释。通过我上面的详细分析,如果对此段程序理解还有困难,可以对比一下没简化之前的程序,细细品味一哈,还是比较容易理解的。要是还理解不了,还是从头再看下,我码这么多字容易吗。。。。。

按位计算CRC代码比较简单,所占内存少,但要一位一位去计算,下面再介绍一种按字节查表快速计算CRC的方法。

3、按字节计算CRC

有了上面按位计算的知识,理解这个就是小case了。还是举前面的例子:当字节计算CRC时,例如计算二进制序列为1001 1010 1010 1111时,即0x9a9f时,将二进制序列数左移16位,即为0x9a9f(0 0 0 0),实际上该二进制序列可拆分为0x9a00(0 0 0 0) + 0x009f(0 0 0 0),分析计算时和上面的步骤一样,唯一不同的是计算中上一步的余数CRC要乘以2的八次方参与

下一步的运算,这个应该好理解撒。为了简化编程,将计算中的CRC拆成高八位和低八位的形式,高八位的值直接与本位值相加求余,低八位的值乘以2的八次方后作为余数和计算得的余数相加。为了提高计算速度,我们把8位二进制序列数的CRC全部计算出来,放在一个表中,采用查表法可大大提高计算速度。

表是怎么得到的呢?当然是计算出来的,下面的程序给出了多项式是0x11021的计算程序。

复制代码 代码如下:

void main( void )

{

unsigned int crc = 0;

unsigned char i;

unsigned int j;

for(j = 0; j < 256; j++) {

crc = 0;

for(i = 0x80; i != 0; i = i >> 1) {

if((crc & 0x8000) != 0) {

crc = crc << 1;

crc = crc ^ 0x1021;

}

else {

crc = crc << 1;

}

if((j & i) != 0) {

crc = crc ^ 0x1021;

}

}

printf("0x");

if(crc < 0x10) {

printf("000");

}

else if(crc < 0x100) {

printf("00");

}

else if(crc < 0x1000) {

printf("0");

}

printf("%x, ",crc);

}

}

如果你不是使用的0x11021多项式,只需把程序中0x1021换成其他的就可以了。后面的几个printf语句为了控制使生成的表比较整齐,如果无所谓,可直接用printf("0x%x, ",crc);代替。生成的表如下:

0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92

f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,

好了,我们来写按字节计算的源程序:

复制代码 代码如下:

unsigned char test[16] ={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};

unsigned char len = 16;

unsigned int crc_table[256] ={

x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};

void main(void)

{

unsigned int crc = 0;

unsigned char crc_H8;

unsigned char *ptr = test;

while( len-- ) {

crc_H8 = (unsigned char)(crc >> 8);

crc = crc << 8;

crc = crc ^ crc_table[

crc_H8 ^ *ptr];

ptr++;

}

printf("0x%x ",crc);

}

4、按半字节计算CRC

是不是感觉上面的表太大了,不是很爽,我们再来改进一下,按半字节计算,原理我就不赘述了,程序如下:

复制代码 代码如下:

unsigned char test[16] ={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};

unsigned char len = 16;

unsigned int crc_table[16] =

{0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef

};

void main(void)

{

unsigned int crc = 0;

unsigned char crc_H4;

unsigned char *ptr = test;

while( len-- )

{

crc_H4 = (unsigned char)(crc >> 12);

crc = crc << 4;

crc = crc ^ crc_table[ crc_H4 ^ (*ptr >> 4)];

crc_H4 = (unsigned char)(crc >> 12);

crc = crc << 4;

crc = crc ^ crc_table[ crc_H4 ^ (*ptr & 0x0f)];

ptr++;

}

printf("0x%x ",crc);

}
您需要登录后才可以回帖 登录 | 点击注册

本版积分规则

魔鬼作坊|易语言教程|易语言源码|易语言论坛|易语言视频教程| 论坛导航|免责申明|手机版||网站地图
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表魔鬼作坊立场!
任何人不得以任何方式翻录、盗版或出售本站视频,一经发现我们将追究其相关责任!
我们一直在努力成为最好的编程论坛!
Copyright© 2010-2019 All Right Reserved.
快速回复 返回顶部 返回列表