【IT】CRC校验码是怎么回事呢?

1. 为什么会有 CRC 校验码?

答:

数据有可能被更改,需要确认是否被更改,且不能占用太多字节,于是有了校验码。

而对一个字节(8位)一个字节的进行循环计算,从而核对数据是否被更改。

2. 修改了一定能被 CRC 校验出来吗?

答:

不是,而是一定概率可以校验出来。

奇偶校验就是属于 CRC 校验一种特例。

所以,为了更好的校验,就有了多项式。

更优的多项式,更高概率检查数据被更改。

经常提到的进行二进制触发计算 CRC,被除数,就是多项式(polynomial)。

  CCITT CRC16 CRC32
校验和位宽W 16 16 32
生成多项式 x16+x12+x5+1 x16+x15+x2+1 x32+x26+x23+x22+x16+ x12+x11+x10+x8+x7+x5+ x4+x2+x1+1
除数(多项式) 0x1021 0x8005 0x04C11DB7
余数初始值 0xFFFF 0x0000 0xFFFFFFFF
结果异或值 0x0000 0x0000 0xFFFFFFFF

3. crc16 算法代码范 表查询法,是怎样的?

 1 #include <stdio.h>
 2 #include <stdint.h>
 3 
 4 #define POLY        0x1021
 5 
 6 uint16_t crc16(unsigned char *addr, int num, uint16_t crc)
 7 {
 8     int i;
 9 
10     while (num--) {
11         crc = crc ^ (*addr++ << 8);
12         for (i = 0; i < 8; i++) {
13             if (crc & 0x8000) {
14                 crc = (crc << 1) ^ POLY;
15             } else {
16                 crc <<= 1;
17             }
18         }
19         crc &= 0xFFFF;
20     }
21     return crc;
22 }
23 
24 int main(void)
25 {
26     uint8_t data[] = {0x02, 0x05};
27 
28     printf("%04X\n", crc16(data, 2, 0xFFFF));
29 
30     return 0;
31 }

4. crc16 是处理部分的逻辑是怎样的?

    a、11 行操作,crc 的低 8 位不变,仅仅是 crc 的高 8 位被修改了

    b、12 行到 18 行:高 8 位决定了会进行多少次与固定数字 POLY(多项式) 的异或操作。

5. 表查询法,是怎么回事呢?

    问:为什么会有表查询法?

    答:因为上面是一个一个 bit 位进行操作。所以在要计算的数据比较多的时候,就很影响效率。

    问:表查询法是如何做到优化的?

    答:

        a、异或操作满足结合律、交换律。与+操作类似。

        b、假设一个8位的数字,分别以 H1、 H2、 H3、 H4、  L1、 L2、 L3、 L4来表示。

              V1、 V2、 V3、 V4、 V5、 V6、 V7、V8 表示 POLY(多项式)的二进制。

                

               上下进行异或操作,高4位决定了低4位会和 POLY 进行多少次异或。

               因异或操作满足结合律、交换律。上面的异或操作与下面的异或操作等价。

               所以,当重复计算比较多的时候,下面的  H1 与 Vx 之间的计算结果可以保存到一个表中,后续直接查询来使用。

               因 CRC 校验是一次处理一字节(8位),所以表格就有 2 的 8 次方 = 256 个。

6、查表法的范例:

 1 #include <stdio.h>
 2 
 3 #include <stdint.h>
 4 
 5 #define POLY    0x1021
 6 #define INIT    0xFFFF
 7 #define FINAL   0x0000
 8 
 9 typedef uint16_t width_t;
10 
11 #define WIDTH   (8 * sizeof(width_t))
12 #define TOPBIT  (1 << (WIDTH - 1))
13 
14 uint16_t crc16(unsigned char *addr, int num, uint16_t crc)
15 {
16     int i;
17 
18     while (num--) {
19         crc = crc ^ (*addr++ << 8);
20         for (i = 0; i < 8; i++) {
21             if (crc & 0x8000) {
22                 crc = (crc << 1) ^ POLY;
23             } else {
24                 crc <<= 1;
25             }
26         }
27         crc &= 0xFFFF;
28     }
29     return crc;
30 }
31 
32 
33 
34 static width_t crc_table[256];
35 
36 void crc_init(void)
37 {
38     width_t reg;
39     width_t i, j;
40 
41     for (i = 0; i < 256; i++) {
42         reg = i << (WIDTH - 8);
43         for(j = 0; j < 8; j++) {
44             if(reg & TOPBIT) {
45                 reg = (reg << 1) ^ POLY;
46             } else {
47                 reg = reg << 1;
48             }
49         }
50         crc_table[i] = reg;
51     }
52 }
53 
54 width_t crc_compute(unsigned char *addr, unsigned int num)
55 {
56     unsigned int i;
57     unsigned int high;    
58     width_t reg = INIT;
59 
60     for (i = 0; i < num; i++) {
61         high = (reg >> (WIDTH - 8)) ^ addr[i];
62         reg = crc_table[high] ^ (reg << 8);
63     }
64 
65     return (reg ^ FINAL);
66 }
67 
68 
69 int main(void)
70 {
71     uint8_t data[] = {0x02, 0x05};
72 
73     printf("%04X\n", crc16(data, 2, 0xFFFF));
74 
75     crc_init();
76     printf("%04X\n", crc_compute(data, 2));
77 
78     return 0;
79 }

参考:

【循环冗余校验(CRC)算法入门引导】https://blog.csdn.net/liyuanbhu/article/details/7882789

【CRC查找表法推导及代码实现比较】https://blog.csdn.net/huang_shiyang/article/details/50881305

【A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS】https://wenku.baidu.com/view/6e700a3b31126edb6f1a1084.html

 【On-line CRC calculation and free library】https://www.lammertbies.nl/comm/info/crc-calculation.html

猜你喜欢

转载自www.cnblogs.com/YBhello/p/11518196.html