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 ...
随机推荐
- SQL Server查询死锁,杀死进程解决死锁
查询死锁进程和表 SELECT request_session_id AS spid , OBJECT_NAME(resource_associated_entity_id) AS 'table' F ...
- Linux停止tomcat运行
打开终端cd /java/tomcat#执行bin/startup.sh #启动tomcatbin/shutdown.sh #停止tomcattail -f logs/catalina.out #看t ...
- ajax请求携带 cookie
之前都有这样一个理解:ajax请求时是不会自动带上cookie的,要是想让他带上的话,必须哟啊设置withCredential为true.这个说法会让人产生完全扭曲的误解,我就是其中之一.完整的无歧义 ...
- Node_进阶_3
Express框架: 一. Express框架 Express框架是后台的Node框架,类似于JS中的jquery. #原生Node开发会有很多问题: 1呈递静态页面很不方便,需要处理每个HTTP ...
- Python2x,3x源码的区别,编译型解释型,变量,注释,if,用户交互input,基本数据类型3种
cpu 内存 硬盘 操作系统 cpu: 计算机的运算和计算中心,相当于人类的大脑. 内存:暂时存储数据,临时加载数据应用程序,4G,8G,16G,32G #速度快,造价高,断电即消失 硬盘 ...
- CodeForces-722C Destroying Array 并查集 离线操作
题目链接:https://cn.vjudge.net/problem/CodeForces-722C 题意 给个数组,每次删除一个元素,删除的元素作为一个隔断,问每次删除后该元素左右两边最大连续和 思 ...
- BZOJ 3530 [SDOI2014]数数 (Trie图/AC自动机+数位DP)
题目大意:略 裸的AC自动机+数位DP吧... 定义f[i][x][0/1]表示已经匹配到了第i位,当前位置是x,0表示没到上限,1到上限,此时数是数量 然而会出现虚拟前导零,即前几位没有数字的情况, ...
- 将页面的内容导出使用html2canvas+jsPDF
第一首先是要引用 import jsPDF from 'jspdf' import html2canvas from 'html2canvas' import PDFJS from 'pdfjs-di ...
- java流与文件的操作 文件加密
课后作业 1,源代码 import java.io.*; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttribu ...
- vue单文件中引用路径的处理
原文地址:vue单文件中引用路径的处理如有错误,欢迎指正! vue单文件的开发过程中,在单文件模版中可能会涉及到文件路径的处理,比如 <img>, style 中的 background ...