热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于CRC效验500分

需要一个CRC效验函数,参数为传入一个字符串、一个字符串长度。求出效验码。其中有个问题,多项式用C005和1021,它们的算法是否一样,如果一样请写一个函数,如果不一样请写两个函数。请用标准C
需要一个CRC效验函数,参数为传入一个字符串、一个字符串长度。

求出效验码。

其中有个问题,多项式用C005和1021,它们的算法是否一样,如果一样请写一个函数,如果不一样请写两个函数。请用标准C++写。

如果写好了,请EMAIL到dev_uoboy@hotmail.com或dev_uoboy@163.net,或直接论坛回复,我验证后会再开贴给分。

7 个解决方案

#1


上面一个EMAIL错了 应该是 dev_uoboy@163.com

#2


500分我还可不敢想,
不过我以前参照了一篇文章也写出来了CRC校验.
具体你还是看看这篇文章吧.



循环冗余校验算法:
1,预置一个16 位寄存器为0xFFFF(全1),称之为CRC寄存器。
2,将数据帧中的第一个8位字节与CRC寄存器中的低字节进行异或运算,结果存会CRC寄存器。
3,将CRC寄存器向右移一位,最高位填0,最低位移出并检测。
4,如果最低位为0:重复第三步(下一次移位)。
   如果最低位为1:将CRC寄存器与一个预设的固定值(0xA001)进行异或运算。
5,重复第三步和第四步直到8次移位。这样处理完了一个完整的八位。
6,重复第2步到第5步来处理下一个八位,直到所有的字节处理结束。
7,最终CRC寄存器的值就是CRC的值。

inline void CRC_STR(BYTE* strFrame,BYTE bLength)
{
WORDtoDBYTE crc;
WORDtoDBYTE y ;
BYTE strTmp[50];
crc.W = 0;

crc.W = CRCTAB[strFrame[0]];
strFrame[1] = bLength; 
y.W = CRCTAB[bLength ^ crc.DB.H];
y.DB.H ^= crc.DB.L;
crc.W = y.W;

y.W = CRCTAB[strFrame[2] ^ crc.DB.H];
y.DB.H ^= crc.DB.L;
crc.W = y.W;

BYTE * pbyte = (BYTE *)(strFrame+3); //指向数据
for(int i = 0; i < (bLength-6)/2; i++)
{
strTmp[i] = *pbyte;
y.W = CRCTAB[*pbyte++ ^ crc.DB.H];
y.DB.H ^= crc.DB.L;
crc.W = y.W;
}

pbyte = (BYTE *)strFrame+3;
for( i = 0; i < (bLength-6)/2; i++)
{
*pbyte++ = strTmp[i]>=0xa0 ? ((strTmp[i]>>4)&0x0f)+0x37 : ((strTmp[i]>>4)&0x0f)+0x30;
strTmp[i] &=0x0f;
*pbyte++ = strTmp[i]>=0x0a ? (strTmp[i]&0x0f)+0x37 : (strTmp[i]&0x0f)+0x30;
}
*pbyte++ = crc.DB.H>=0xa0 ? ((crc.DB.H>>4)&0x0f)+0x37 : ((crc.DB.H>>4)&0x0f)+0x30;
*pbyte++ = (crc.DB.H&0x0f)>=0x0a ? (crc.DB.H&0x0f)+0x37 : (crc.DB.H&0x0f)+0x30;
*pbyte++ = crc.DB.L>=0xa0 ? ((crc.DB.L>>4)&0x0f)+0x37 : ((crc.DB.L>>4)&0x0f)+0x30;
*pbyte++ = (crc.DB.L&0x0f)>=0x0a ? (crc.DB.L&0x0f)+0x37 : (crc.DB.L&0x0f)+0x30;
*pbyte = 0;
}
只是我对他们进行拆分了



#3










摘 要  本文从理论上推导出CRC算法实现原理,给出三种分别适应不同计算机或微控制器硬件环境的C语言程序。读者更能根据本算法原理,用不同的语言编写出独特风格更加实用的CRC计算程序。
关键词   CRC   算法   C语言
1  引言
     循环冗余码CRC检验技术广泛应用于测控及通信领域。CRC计算可以靠专用的硬件来实现,但是对于低成本的微控制器系统,在没有硬件支持下实现CRC检验,关键的问题就是如何通过软件来完成CRC计算,也就是CRC算法的问题。
    这里将提供三种算法,它们稍有不同,一种适用于程序空间十分苛刻但CRC计算速度要求不高的微控制器系统,另一种适用于程序空间较大且CRC计算速度要求较高的计算机或微控制器系统,最后一种是适用于程序空间不太大,且CRC计算速度又不可以太慢的微控制器系统。
2  CRC简介
CRC校验的基本思想是利用线性编码理论,在发送端根据要传送的k位二进制码序列,以一定的规则产生一个校验用的监督码(既CRC码)r位,并附在信息后边,构成一个新的二进制码序列数共(k+r)位,最后发送出去。在接收端,则根据信息码和CRC码之间所遵循的规则进行检验,以确定传送中是否出错。
16位的CRC码产生的规则是先将要发送的二进制序列数左移16位(既乘以 )后,再除以一个多项式,最后所得到的余数既是CRC码,如式(2-1)式所示,其中B(X)表示n位的二进制序列数,G(X)为多项式,Q(X)为整数,R(X)是余数(既CRC码)。
                        (2-1)
求CRC码所采用模2加减运算法则,既是不带进位和借位的按位加减,这种加减运算实际上就是逻辑上的异或运算,加法和减法等价,乘法和除法运算与普通代数式的乘除法运算是一样,符合同样的规律。生成CRC码的多项式如下,其中CRC-16和CRC-CCITT产生16位的CRC码,而CRC-32则产生的是32位的CRC码。本文不讨论32位的CRC算法,有兴趣的朋友可以根据本文的思路自己去推导计算方法。
CRC-16:(美国二进制同步系统中采用)   
CRC-CCITT:(由欧洲CCITT推荐)        
CRC-32:    

接收方将接收到的二进制序列数(包括信息码和CRC码)除以多项式,如果余数为0,则说明传输中无错误发生,否则说明传输有误,关于其原理这里不再多述。用软件计算CRC码时,接收方可以将接收到的信息码求CRC码,比较结果和接收到的CRC码是否相同。

3  按位计算CRC
对于一个二进制序列数可以表示为式(3-1):
                            (3-1)
求此二进制序列数的CRC码时,先乘以 后(既左移16位),再除以多项式G(X),所得的余数既是所要求的CRC码。如式(3-2)所示:
          (3-2)
可以设:                                                (3-3)
其中 为整数, 为16位二进制余数。将式(3-3)代入式(3-2)得:

      (3-4)
再设:                                   (3-5)
其中 为整数, 为16位二进制余数,将式(3-5)代入式(3-4),如上类推,最后得到:
   (3-6)
根据CRC的定义,很显然,十六位二进制数 既是我们要求的CRC码。
式(3-5)是编程计算CRC的关键,它说明计算本位后的CRC码等于上一位CRC码乘以2后除以多项式,所得的余数再加上本位值除以多项式所得的余数。由此不难理解下面求CRC码的C语言程序。*ptr指向发送缓冲区的首字节,len是要发送的总字节数,0x1021与多项式有关。
unsigned int cal_crc(unsigned char *ptr, unsigned char len) {
  unsigned char i;
  unsigned int crc=0;
  while(len--!=0) {
    for(i=0x80; i!=0; i/=2) {
      if((crc&0x8000)!=0) {crc*=2; crc^=0x1021;}   /* 余式CRC乘以2再求CRC  */
        else crc*=2;
if((*ptr&i)!=0) crc^=0x1021;                /* 再加上本位的CRC */
    }
    ptr++;
  }
  return(crc);
}
  按位计算CRC虽然代码简单,所占用的内存比较少,但其最大的缺点就是一位一位地计算会占用很多的处理器处理时间,尤其在高速通讯的场合,这个缺点更是不可容忍。因此下面再介绍一种按字节查表快速计算CRC的方法。
4  按字节计算CRC
不难理解,对于一个二进制序列数可以按字节表示为式(4-1),其中 为一个字节(共8位)。
               (4-1)
求此二进制序列数的CRC码时,先乘以 后(既左移16位),再除以多项式G(X),所得的余数既是所要求的CRC码。如式(4-2)所示:
              (4-2)
可以设:                                            (4-3)
其中 为整数, 为16位二进制余数。将式(4-3)代入式(4-2)得:
                    (4-4)
因为:       
                                                    (4-5)
其中 是 的高八位, 是 的低八位。将式(4-5)代入式(4-4),经整理后得:
                                                                               (4-6)
再设:                 (4-7)
其中 为整数, 为16位二进制余数。将式(4-7)代入式(4-6),如上类推,最后得:
                (4-8)
很显然,十六位二进制数 既是我们要求的CRC码。
式(4-7)是编写按字节计算CRC程序的关键,它说明计算本字节后的CRC码等于上一字节余式CRC码的低8位左移8位后,再加上上一字节CRC右移8位(也既取高8位)和本字节之和后所求得的CRC码,如果我们把8位二进制序列数的CRC全部计算出来,放如一个表里,采用查表法,可以大大提高计算速度。由此不难理解下面按字节求CRC码的C语言程序。*ptr指向发送缓冲区的首字节,len是要发送的总字节数,CRC余式表是按0x11021多项式求出的。
unsigned int cal_crc(unsigned char *ptr,  unsigned char len) {
  unsigned int crc;
  unsigned char da;
  unsigned int crc_ta[256]={               /* CRC余式表 */
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x 1231, 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
  };

  crc=0;
  while(len--!=0) {
    da=(uchar) (crc/256);    /* 以8位二进制数的形式暂存CRC的高8位 */
    crc<<=8;              /* 左移8位,相当于CRC的低8位乘以  */
    crc^=crc_ta[da^*ptr];   /* 高8位和当前字节相加后再查表求CRC ,再加上以前的CRC */
    ptr++;
  }
  return(crc);
}
很显然,按字节求CRC时,由于采用了查表法,大大提高了计算速度。但对于广泛运用的8位微处理器,代码空间有限,对于要求256个CRC余式表(共512字节的内存)已经显得捉襟见肘了,但CRC的计算速度又不可以太慢,因此再介绍下面一种按半字节求CRC的算法。
5  按半字节计算CRC
同样道理,对于一个二进制序列数可以按字节表示为式(5-1),其中 为半个字节(共4位)。
              (5-1)
求此二进制序列数的CRC码时,先乘以 后(既左移16位),再除以多项式G(X),所得的余数既是所要求的CRC码。如式(4-2)所示:
              (5-2)
可以设:                                            (5-3)
其中 为整数, 为16位二进制余数。将式(5-3)代入式(5-2)得:
                    (5-4)
因为:       
                                                    (5-5)
其中 是 的高4位, 是 的低12位。将式(5-5)代入式(5-4),经整理后得:
                                                                               (5-6)
再设

#4


ding

#5


xiaowei27(小阿伟) :
   越来越厉害了

#6


没有其他人了???

#7


const unsigned short cnCRC_16    = 0x8005;
    const unsigned short cnCRC_CCITT = 0x1021;
    const unsigned long  cnCRC_32    = 0x04C10DB7;
    // CRC-32    = X32 + X26 + X23 + X22 + X16 + X11 + X10 + X8 + X7 + X5 + X4 + X2 + X1 + X0

unsigned long Table_CRC[256]; // CRC 表

//  构造 16 位 CRC 表
void BuildTable16( unsigned short aPoly )
{
    unsigned short i, j;
    unsigned short nData;
    unsigned short nAccum;

    for ( i = 0; i < 256; i++ )
    {
        nData = ( unsigned short )( i << 8 );
        nAccum = 0;
        for ( j = 0; j < 8; j++ )
        {
            if ( ( nData ^ nAccum ) & 0x8000 )
                nAccum = ( nAccum << 1 ) ^ aPoly;
            else
                nAccum <<= 1;
            nData <<= 1;
        }
        Table_CRC[i] = ( unsigned long )nAccum;
    }
}

//  计算 16 位 CRC 值,CRC-16 或 CRC-CCITT
unsigned short CRC_16( unsigned char * aData, unsigned long aSize )
{
    unsigned long  i;
    unsigned short nAccum = 0;

    BuildTable16( cnCRC_16 ); //  or cnCRC_CCITT
    for ( i = 0; i < aSize; i++ )
        nAccum = ( nAccum << 8 ) ^ ( unsigned short )Table_CRC[( nAccum >> 8 ) ^ *aData++];
    return nAccum;
}


推荐阅读
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了最长上升子序列问题的一个变种解法,通过记录拐点的位置,将问题拆分为左右两个LIS问题。详细讲解了算法的实现过程,并给出了相应的代码。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • C语言判断正整数能否被整除的程序
    本文介绍了使用C语言编写的判断正整数能否被整除的程序,包括输入一个三位正整数,判断是否能被3整除且至少包含数字3的方法。同时还介绍了使用qsort函数进行快速排序的算法。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • C语言常量与变量的深入理解及其影响
    本文深入讲解了C语言中常量与变量的概念及其深入实质,强调了对常量和变量的理解对于学习指针等后续内容的重要性。详细介绍了常量的分类和特点,以及变量的定义和分类。同时指出了常量和变量在程序中的作用及其对内存空间的影响,类似于const关键字的只读属性。此外,还提及了常量和变量在实际应用中可能出现的问题,如段错误和野指针。 ... [详细]
  • 本文介绍了解决java开源项目apache commons email简单使用报错的方法,包括使用正确的JAR包和正确的代码配置,以及相关参数的设置。详细介绍了如何使用apache commons email发送邮件。 ... [详细]
  • C语言自带的快排和二分查找
    Author🚹:CofCaiEmail✉️:cai.dongjunnexuslink.cnQQ😙:1664866311personalPage&#x ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • Android日历提醒软件开源项目分享及使用教程
    本文介绍了一款名为Android日历提醒软件的开源项目,作者分享了该项目的代码和使用教程,并提供了GitHub项目地址。文章详细介绍了该软件的主界面风格、日程信息的分类查看功能,以及添加日程提醒和查看详情的界面。同时,作者还提醒了读者在使用过程中可能遇到的Android6.0权限问题,并提供了解决方法。 ... [详细]
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
author-avatar
NAVETEX
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有