常用多项式:

生成多项式的选取应满足以下条件:

    a、生成多项式的最高位和最低位必须为1。

    b、当被传送信息(CRC码)任何一位发生错误时,被生成多项式做模2除后,应该使余数不为0。

    c、不同位发生错误时,应该使余数不同。

    d、对余数继续做模2除,应使余数循环。

主要的生成多项式G(x)有以下几种:

名称

生成多项式

数值式

简记式

标准引用

CRC-16

x16+x15+x2+1

0x1’8005

8005

IBM SDLC

CRC-CCITT

x16+x12+x5+1

0X1’1021

0x1021

ISO HDLC,ITU X.25,V.34/V.41/V.42,PPP-FCS

CRC-32

注*

0X1’04C11DB7

0x04C11DB7

ZIP,RAR,IEEE 802 LAN/FDDI,IEEE1394,PPP-FCS

注*  x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1

下表中的生成多项式G(x)也常见的:

名称

生成多项式

数值式

简记式

标准引用

CRC-4

x4+x+1

0x1’3

0x3

ITU G.704

CRC-8

x8+x5+x4+1

0x1’31

0x31

 

CRC-8

x8+x2+x1+1

0x1’07

0x07

 

CRC-8

x8+x6+x4+x3+x2+x1

0x1’5E

0x5E

 

CRC-12

x12+x11+x3+x2+x+1

0x1’80F

0x80F

 

CRC-32c

注**

0X1’1EDC6F41

0x1EDC6F41

SCTP

注** x32+x28+x27+x26+x25+x23+x22+x20+x19+x18+x14+x13+x11+x10+x9+x8+x6+1

示例代码

16位实现代码

#include<stdio.h>

#define crc_mul 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>>=1)
        {
            if((crc&0x8000)!=0)
            {
               crc<<=1;
               crc^=(crc_mul);
            }else{
               crc<<=1;
            }
            if((*ptr&i)!=0)
            {
               crc ^= (crc_mul);
            }
        }
        ptr ++;
    }
    return (crc);
}

int main()
{
    unsigned char i[8] = {0x00,0x00,0x00,0x00,0x06,0x0d,0xd2,0xe3};
    unsigned int crc;
    crc=cal_crc(i,8);
    return 0;
} 
/*结果:7123dbc0*/

CRC32代码实现

#include<stdio.h>
unsigned int CRC32_table[256] = {0};
void init_CRC32_table()
{
  for (int i = 0; i != 256; i++)
  {
    unsigned int CRC = i;
    for (int j = 0; j != 8; j++)
    {
      if (CRC & 1)
        CRC = (CRC >> 1) ^ 0xEDB88320;
      else
        CRC >>= 1;
    }
    CRC32_table[i] = CRC;
  }
}
unsigned int GetCRC32(unsigned char* buf, unsigned int len)
{
  unsigned int CRC32_data = 0xFFFFFFFF;
  for (unsigned int i = 0; i != len; ++i)
  {
    unsigned int t = (CRC32_data ^ buf[i]) & 0xFF;
    CRC32_data = ((CRC32_data >> 8) & 0xFFFFFF) ^ CRC32_table[t];
  }
  return ~CRC32_data;
}

int main()
{
    unsigned char i[8] = {0x00,0x00,0x00,0x00,0x06,0x0d,0xd2,0xe3};
    init_CRC32_table();
    printf("BUFFER i's CRC32: 0x%x\n", GetCRC32(i,8));
    printf("CRC32 TABLE:\n");
    for(int i=0;i<256;i++)
    {
         printf("0x%8x\t",CRC32_table[i]);
         if((i+1)%8 == 0)
             printf("\n");
    }
} 
/*结果如下:
BUFFER i's CRC32: 0xc29c07b9
CRC32 TABLE:
0x       0	0x77073096	0xee0e612c	0x990951ba	0x 76dc419	0x706af48f	0xe963a535	0x9e6495a3	
0x edb8832	0x79dcb8a4	0xe0d5e91e	0x97d2d988	0x 9b64c2b	0x7eb17cbd	0xe7b82d07	0x90bf1d91	
0x1db71064	0x6ab020f2	0xf3b97148	0x84be41de	0x1adad47d	0x6ddde4eb	0xf4d4b551	0x83d385c7	
0x136c9856	0x646ba8c0	0xfd62f97a	0x8a65c9ec	0x14015c4f	0x63066cd9	0xfa0f3d63	0x8d080df5	
0x3b6e20c8	0x4c69105e	0xd56041e4	0xa2677172	0x3c03e4d1	0x4b04d447	0xd20d85fd	0xa50ab56b	
0x35b5a8fa	0x42b2986c	0xdbbbc9d6	0xacbcf940	0x32d86ce3	0x45df5c75	0xdcd60dcf	0xabd13d59	
0x26d930ac	0x51de003a	0xc8d75180	0xbfd06116	0x21b4f4b5	0x56b3c423	0xcfba9599	0xb8bda50f	
0x2802b89e	0x5f058808	0xc60cd9b2	0xb10be924	0x2f6f7c87	0x58684c11	0xc1611dab	0xb6662d3d	
0x76dc4190	0x 1db7106	0x98d220bc	0xefd5102a	0x71b18589	0x 6b6b51f	0x9fbfe4a5	0xe8b8d433	
0x7807c9a2	0x f00f934	0x9609a88e	0xe10e9818	0x7f6a0dbb	0x 86d3d2d	0x91646c97	0xe6635c01	
0x6b6b51f4	0x1c6c6162	0x856530d8	0xf262004e	0x6c0695ed	0x1b01a57b	0x8208f4c1	0xf50fc457	
0x65b0d9c6	0x12b7e950	0x8bbeb8ea	0xfcb9887c	0x62dd1ddf	0x15da2d49	0x8cd37cf3	0xfbd44c65	
0x4db26158	0x3ab551ce	0xa3bc0074	0xd4bb30e2	0x4adfa541	0x3dd895d7	0xa4d1c46d	0xd3d6f4fb	
0x4369e96a	0x346ed9fc	0xad678846	0xda60b8d0	0x44042d73	0x33031de5	0xaa0a4c5f	0xdd0d7cc9	
0x5005713c	0x270241aa	0xbe0b1010	0xc90c2086	0x5768b525	0x206f85b3	0xb966d409	0xce61e49f	
0x5edef90e	0x29d9c998	0xb0d09822	0xc7d7a8b4	0x59b33d17	0x2eb40d81	0xb7bd5c3b	0xc0ba6cad	
0xedb88320	0x9abfb3b6	0x 3b6e20c	0x74b1d29a	0xead54739	0x9dd277af	0x 4db2615	0x73dc1683	
0xe3630b12	0x94643b84	0x d6d6a3e	0x7a6a5aa8	0xe40ecf0b	0x9309ff9d	0x a00ae27	0x7d079eb1	
0xf00f9344	0x8708a3d2	0x1e01f268	0x6906c2fe	0xf762575d	0x806567cb	0x196c3671	0x6e6b06e7	
0xfed41b76	0x89d32be0	0x10da7a5a	0x67dd4acc	0xf9b9df6f	0x8ebeeff9	0x17b7be43	0x60b08ed5	
0xd6d6a3e8	0xa1d1937e	0x38d8c2c4	0x4fdff252	0xd1bb67f1	0xa6bc5767	0x3fb506dd	0x48b2364b	
0xd80d2bda	0xaf0a1b4c	0x36034af6	0x41047a60	0xdf60efc3	0xa867df55	0x316e8eef	0x4669be79	
0xcb61b38c	0xbc66831a	0x256fd2a0	0x5268e236	0xcc0c7795	0xbb0b4703	0x220216b9	0x5505262f	
0xc5ba3bbe	0xb2bd0b28	0x2bb45a92	0x5cb36a04	0xc2d7ffa7	0xb5d0cf31	0x2cd99e8b	0x5bdeae1d	
0x9b64c2b0	0xec63f226	0x756aa39c	0x 26d930a	0x9c0906a9	0xeb0e363f	0x72076785	0x 5005713	
0x95bf4a82	0xe2b87a14	0x7bb12bae	0x cb61b38	0x92d28e9b	0xe5d5be0d	0x7cdcefb7	0x bdbdf21	
0x86d3d2d4	0xf1d4e242	0x68ddb3f8	0x1fda836e	0x81be16cd	0xf6b9265b	0x6fb077e1	0x18b74777	
0x88085ae6	0xff0f6a70	0x66063bca	0x11010b5c	0x8f659eff	0xf862ae69	0x616bffd3	0x166ccf45	
0xa00ae278	0xd70dd2ee	0x4e048354	0x3903b3c2	0xa7672661	0xd06016f7	0x4969474d	0x3e6e77db	
0xaed16a4a	0xd9d65adc	0x40df0b66	0x37d83bf0	0xa9bcae53	0xdebb9ec5	0x47b2cf7f	0x30b5ffe9	
0xbdbdf21c	0xcabac28a	0x53b39330	0x24b4a3a6	0xbad03605	0xcdd70693	0x54de5729	0x23d967bf	
0xb3667a2e	0xc4614ab8	0x5d681b02	0x2a6f2b94	0xb40bbe37	0xc30c8ea1	0x5a05df1b	0x2d02ef8d
*/

其实,世界上一共就256个字符,每装载一个就运算一遍,实在是浪费CPU,不如直接把每个字符的CRC都算出来存入数组。因此,就有了CRC编码字符表。

原理

在k位信息码后再拼接r位的校验码,报文编码长度为n位,因此,这种编码又叫(n,k)码。

定理:对于一个给定的(nk)码,可以证明,存在一个最高次幂为n=k+r的多项式G(x)存在且仅存在一个R次多项式G(x),使得

lua语言file_copy LUA语言crc多项式怎么计算_多项式

其中:

m(x) :k次信息多项式,

r(x) :r-1次校验多项式,

g(x):生成多项式:

lua语言file_copy LUA语言crc多项式怎么计算_2d_02


发送方通过指定的G(x)产生r位的CRC校验码,接收方则通过该G(x)来验证收到的报文码的CRC校验码是否为0。

    假设发送信息用信息多项式C(X)表示,将C(x)左移r位,则可表示成C(x)*2r,这样C(x)的右边就会空出r位校验码的位置,做除法(模2除)

lua语言file_copy LUA语言crc多项式怎么计算_2d_03

,得到的余数R就是校验码。发送的CRC编码是

lua语言file_copy LUA语言crc多项式怎么计算_3d_04

,验证接收到的报文编码是否至正确,依然是做模2除:

lua语言file_copy LUA语言crc多项式怎么计算_3d_05


计算过程

生成多项式:G(X)=X4+X3+1,要求出二进制序列10110011的CRC校验码。

(1)G(X)=X4+X3+1,二进制比特串为11001;(有X的几次方,对应的2的几次方的位就是1)

(2)因为校验码4位,所以10110011后面再加4个0,得到101100110000,用“模2除法”(其实就是亦或^)即可得出结果;

 

lua语言file_copy LUA语言crc多项式怎么计算_多项式_06

                                            图5-10 CRC校验码计算示例

 (3)CRC^101100110000得到101100110100。发送到接收端;

 (4)接收端收到101100110100后除以11001(以“模2除法”方式去除),余数为0则无差错;