CRC校验的C语言实现
文章转自 循环冗余校验(CRC)算法入门引导 - Ivan 的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/liyuanbhu/article/details/7882789
一、原理部分
CRC 算法的基本思想是将传输的数据当做一个位数很长的数,将这个数除以另一个数,得到的余数作为校验数据附加到原数据后面。除法采用正常的多项式乘除法,而加减法都采用模2运算。模2运算就是结果除以2后取余数,如3 mod 2 = 1,在计算机中就是异或运算:
例如:
要传输的数据为:1101011011
除数设为:10011
在计算前先将原始数据后面填上4个0:11010110110000,之所以要补0,补0的个数就是得到的余数位数。

采用了模2的加减法后,不需要考虑借位的问题。最后得到的余数就是CRC 校验字。为了进行CRC运算,也就是这种特殊的除法运算,必须要指定个被除数,在CRC算法中,这个被除数有一个专有名称叫做“生成多项式”。文献中提到的生成多项式经常会说到多项式的位宽(Width,简记为W),这个位宽不是多项式对应的二进制数的位数,而是位数减1。比如CRC8中用到的位宽为8的生成多项式,其实对应得二进制数有九位:100110001。
二、编程实现
假设我们的生成多项式为:100110001(简记为0x31),也就是CRC-8
则计算步骤如下:
(1) 将CRC寄存器(8-bits,比生成多项式少1bit)赋初值0
(2) 在待传输信息流后面加入8个0
(3) While (数据未处理完)
(4) Begin
(5) If (CRC寄存器首位是1)
(6) reg = reg XOR 0x31
(7) CRC寄存器左移一位,读入一个新的数据于CRC寄存器的0 bit的位置。
(8) End
(9) CRC寄存器就是我们所要求的余数。
实际上,真正的CRC 计算通常与上面描述的还有些出入。这是因为这种最基本的CRC除法有个很明显的缺陷,就是数据流的开头添加一些0并不影响最后校验字的结果。因此真正应用的CRC 算法基本都在原始的CRC算法的基础上做了些小的改动。
所谓的改动,也就是增加了两个概念,第一个是“余数初始值”,第二个是“结果异或值”。
所谓的“余数初始值”就是在计算CRC值的开始,给CRC寄存器一个初始值。“结果异或值”是在其余计算完成后将CRC寄存器的值在与这个值进行一下异或操作作为最后的校验值。
常见的三种CRC 标准用到个各个参数如下表。
|
|
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 |
加入这些变形后,常见的算法描述形式就成了这个样子了:
(1) 设置CRC寄存器,并给其赋值为“余数初始值”。
while(数据未处理完)
begin(8_bit)
(2) 将数据的第一个8-bit字符与CRC寄存器进行异或,并把结果存入CRC寄存器。
(3) CRC寄存器向右移一位,MSB补零,移出并检查LSB。
(4) 如果LSB为0,重复第三步;若LSB为1,CRC寄存器与0x31相异或。
(5) 重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕。
end(8-bit)
(6) 重复第2至第5步直到所有数据全部处理完成。
(7) 最终CRC寄存器的内容与“结果异或值”进行或非操作后即为CRC值。
示例性的C代码如下所示,因为效率很低,项目中如对计算时间有要求应该避免采用这样的代码。这个代码有一个crc的参数,可以将上次计算的crc结果传入函数中作为这次计算的初始值,这对大数据块的CRC计算是很有用的,不需要一次将所有数据读入内存,而是读一部分算一次,全读完后就计算完了。这对内存受限系统还是很有用的。
- #define POLY 0x1021
- /**
- * Calculating CRC-16 in 'C'
- * @para addr, start of data
- * @para num, length of data
- * @para crc, incoming CRC
- */
- uint16_t crc16(unsigned char *addr, int num, uint16_t crc)
- {
- int i;
- for (; num > 0; num--) /* Step through bytes in memory */
- {
- crc = crc ^ (*addr++ << 8); /* Fetch byte from memory, XOR into CRC top byte*/
- for (i = 0; i < 8; i++) /* Prepare to rotate 8 bits */
- {
- if (crc & 0x8000) /* b15 is set... */
- crc = (crc << 1) ^ POLY; /* rotate and XOR with polynomic */
- else /* b15 is clear... */
- crc <<= 1; /* just rotate */
- } /* Loop for 8 bits */
- crc &= 0xFFFF; /* Ensure CRC remains 16-bit value */
- } /* Loop until num=0 */
- return(crc); /* Return updated CRC */
- }
上面的算法对数据流逐位进行计算,效率很低。实际上仔细分析CRC计算的数学性质后我们可以多位多位计算,最常用的是一种按字节查表的快速算法。该算法基于这样一个事实:计算本字节后的CRC码,等于上一字节余式CRC码的低8位左移8位,加上上一字节CRC右移 8位和本字节之和后所求得的CRC码。如果我们把8位二进制序列数的CRC(共256个)全部计算出来,放在一个表里,编码时只要从表中查找对应的值进行处理即可。
按照这个方法,可以有如下的代码(这个代码来自Micbael Barr的书“Programming Embedded Systems in C and C++” ):
- /*
- crc.h
- */
- #ifndef CRC_H_INCLUDED
- #define CRC_H_INCLUDED
- /*
- * The CRC parameters. Currently configured for CCITT.
- * Simply modify these to switch to another CRC Standard.
- */
- /*
- #define POLYNOMIAL 0x8005
- #define INITIAL_REMAINDER 0x0000
- #define FINAL_XOR_VALUE 0x0000
- */
- #define POLYNOMIAL 0x1021
- #define INITIAL_REMAINDER 0xFFFF
- #define FINAL_XOR_VALUE 0x0000
- /*
- #define POLYNOMIAL 0x1021
- #define POLYNOMIAL 0xA001
- #define INITIAL_REMAINDER 0xFFFF
- #define FINAL_XOR_VALUE 0x0000
- */
- /*
- * The width of the CRC calculation and result.
- * Modify the typedef for an 8 or 32-bit CRC standard.
- */
- typedef unsigned short width_t;
- #define WIDTH (8 * sizeof(width_t))
- #define TOPBIT (1 << (WIDTH - 1))
- /**
- * Initialize the CRC lookup table.
- * This table is used by crcCompute() to make CRC computation faster.
- */
- void crcInit(void);
- /**
- * Compute the CRC checksum of a binary message block.
- * @para message, 用来计算的数据
- * @para nBytes, 数据的长度
- * @note This function expects that crcInit() has been called
- * first to initialize the CRC lookup table.
- */
- width_t crcCompute(unsigned char * message, unsigned int nBytes);
- #endif // CRC_H_INCLUDED
- /*
- *crc.c
- */
- #include "crc.h"
- /*
- * An array containing the pre-computed intermediate result for each
- * possible byte of input. This is used to speed up the computation.
- */
- static width_t crcTable[256];
- /**
- * Initialize the CRC lookup table.
- * This table is used by crcCompute() to make CRC computation faster.
- */
- void crcInit(void)
- {
- width_t remainder;
- width_t dividend;
- int bit;
- /* Perform binary long division, a bit at a time. */
- for(dividend = 0; dividend < 256; dividend++)
- {
- /* Initialize the remainder. */
- remainder = dividend << (WIDTH - 8);
- /* Shift and XOR with the polynomial. */
- for(bit = 0; bit < 8; bit++)
- {
- /* Try to divide the current data bit. */
- if(remainder & TOPBIT)
- {
- remainder = (remainder << 1) ^ POLYNOMIAL;
- }
- else
- {
- remainder = remainder << 1;
- }
- }
- /* Save the result in the table. */
- crcTable[dividend] = remainder;
- }
- } /* crcInit() */
- /**
- * Compute the CRC checksum of a binary message block.
- * @para message, 用来计算的数据
- * @para nBytes, 数据的长度
- * @note This function expects that crcInit() has been called
- * first to initialize the CRC lookup table.
- */
- width_t crcCompute(unsigned char * message, unsigned int nBytes)
- {
- unsigned int offset;
- unsigned char byte;
- width_t remainder = INITIAL_REMAINDER;
- /* Divide the message by the polynomial, a byte at a time. */
- for( offset = 0; offset < nBytes; offset++)
- {
- byte = (remainder >> (WIDTH - 8)) ^ message[offset];
- remainder = crcTable[byte] ^ (remainder << 8);
- }
- /* The final remainder is the CRC result. */
- return (remainder ^ FINAL_XOR_VALUE);
- } /* crcCompute() */
上面代码中crcInit() 函数用来计算crcTable,因此在调用 crcCompute 前必须先调用 crcInit()。
CRC校验的C语言实现的更多相关文章
- Verilog语言实现并行(循环冗余码)CRC校验
1 前言 (1) 什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错功能, ...
- CRC校验代码实现
1.CRC校验简介 CRC就是块数据的计算值,它的全称是“Cyclic Redundancy Check”,中文名是“循环冗余码”.CRC校验是数据通讯中最常采用的校验方式.在嵌入式软件开发中,经常要 ...
- 字符串CRC校验
字符串CRC校验 <pre name="code" class="python"><span style="font-family: ...
- 协议栈中使用crc校验函数
CRC校验介绍:循环冗余校验码,原理是多项式除法 ZigBee协议栈:能够使zigbee节点相互之间组网,数据传输,数据获取,数据显示 思路以及步骤: 1.因为IAR的程序是用c写的,所以上网查找如何 ...
- CEIWEI CheckSum CRC校验精灵v2.1 CRC3/CRC4/CRC5/CRC6/CRC8CRC10/CRC11/CRC16/CRC24/CRC32/CRC40/CRC64/CRC82/Adler32
CEIWEI CheckSum CRC校验精灵 是一款通用的循环冗余校验码CRC(Cyclic Redundancy Check).MD5.SHA1.SHA2.SHA3.HAVAL.SHAKE.TIG ...
- CRC校验原理和verilog实现方法(一)
1.CRC简介 CRC全称循环冗余校验(Cyclic Redundancy Check, CRC),是通信领域数据传输技术中常用的检错方法,用于保证数据传输的可靠性.网上有关这方面的博客和资料很多,本 ...
- 文档:网络通讯包结构(crc校验,加解密)
一直想把这个流程整理一下. 包结构: 包 对(datacrc+protoID+dataSize)组成的byte[] 进行crc计算而得到 对(数据内容)进行crc计算而得到 协议号 数据内容的字节长度 ...
- CRC校验码原理、实例、手动计算
目录一.CRC16实现代码二.CRC32编码字符表三.CRC校验码的手动计算示例四.CRC校验原理五.CRC的生成多项式参考 一.CRC16实现代码 思路:取一个字符(8bit),逐位检查该字符,如果 ...
- 物联网平台设计心得:你所不知道的CRC校验
在物联网平台设计过程中,我的中间件一方面需要处理来自于硬件端的包,另一方面需要处理来自于用户端的包,用户端包括web端和手机端等等.所以编写一个统一的CRC认证是非常必须要. 那么,在设计开始,CRC ...
随机推荐
- Codeforces 986B. Petr and Permutations(没想到这道2250分的题这么简单,早知道就先做了)
这题真的只能靠直觉了,我没法给出详细证明. 解题思路: 1.交换3n次或者7n+1次,一定会出现一个为奇数,另一个为偶数. 2.用最朴素的方法,将n个数字归位,计算交换次数. 3.判断交换次数是否与3 ...
- STM8S103-STVD建立汇编代码项目
转载:http://blog.csdn.net/u010093140/article/details/49983397 STVD本来就比较少人用,STVD汇编就更少人用了,不过STM8汇编我自己还是满 ...
- java上传文件工具类
这个是之前整理之前所学时与使用java向邮箱发送邮件一块找到的,一起贴出来供大家参考: import java.awt.image.BufferedImage; import java.io.File ...
- Django综合基础知识
Django框架简介 MVC框架和MTV框架 MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View) ...
- redis搭建与安装
redis提供五种数据类型:string,hash,list,set及zset(sorted set). 第一部分:安装redis 希望将redis安装到此目录 1 /usr/local/redis ...
- UNIX系统高级编程——第五章-标准I/O库-总结
基础: 标准I/O库在ANSI C中定义,可移植在不同的系统 文件指针(FILE):标准I/O库操作的不是文件描述符,而是流.FILE文件指针包含的是维护流所需的信息 通过函数fileno获取流的文件 ...
- poj-2758 Checking the Text
题意: 给定一个字符串,要求维护两种操作: I:在字符串中插入一个字符: Q:询问某两个位置開始的LCP. 插入操作<=200,字符串长度<=5w,查询操作<=2w: 题解: 第一道 ...
- 【POJ 2750】 Potted Flower(线段树套dp)
[POJ 2750] Potted Flower(线段树套dp) Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4566 ...
- bzoj3931: [CQOI2015]网络吞吐量(spfa+网络流)
3931: [CQOI2015]网络吞吐量 题目:传送门 题解: 现在有点难受....跳了一个多钟...菜啊... 题意都把做法一起给了....最短路+网路流啊. 不想说话...记得开long lon ...
- hpuoj--校赛--面试难题(区间相交问题)
问题 F: 感恩节KK专场--面试难题 时间限制: 1 Sec 内存限制: 128 MB 提交: 294 解决: 39 [提交][状态][讨论版] 题目描述 有n个人要来面试学生会XX部门,要求面 ...