CRC算法原理
- 格式:doc
- 大小:375.50 KB
- 文档页数:90
CRC算法原理及C语言实现CRC(Cyclic Redundancy Check)循环冗余校验算法是一种常用的错误检测算法,广泛应用于数据通信、存储等领域。
它通过对发送的数据进行多项式计算,得到一个校验值,然后将这个校验值附加到数据末尾,接收方再进行校验,通过比较接收到的校验值和重新计算的校验值来判断数据是否出现错误。
本文将介绍CRC算法的原理以及如何使用C语言实现。
一、CRC算法原理1.多项式表示CRC算法使用一个多项式来进行计算,这个多项式称为校验多项式(Generator Polynomial)。
在CRC算法中,校验多项式是一个二进制数,其中最高位为1,低位为0。
例如,CRC-32算法的校验多项式是0x04C11DB72.计算过程(1)初始化:将校验值设为一个固定的初始值,通常为全为0的二进制数。
(2)数据处理:逐位处理输入的数据,包括附加校验值的数据。
(3)除法运算:对每一位数据按位异或,然后进行除法运算,取余数。
(4)更新校验值:将余数与下一位数据进行异或运算,再将结果作为新的校验值。
(5)重复上述步骤,直到处理完所有的数据。
3.校验结果CRC算法的校验结果即为最后得到的校验值。
在进行校验时,接收方使用相同的校验多项式,对接收到的数据进行相同的操作,得到的校验值与发送方发送的校验值进行比较,如果相同,则说明数据未发生错误,否则则说明数据出现了错误。
二、C语言实现CRC算法下面是一个简单的C语言实现CRC算法的例子,以CRC-32算法为例:```c#include <stdio.h>//初始化校验值unsigned int crc32_inireturn 0xFFFFFFFF;//计算CRC值unsigned int i, j;for (i = 0; i < length; i++)crc = crc ^ data[i];for (j = 0; j < 8; j++)if ((crc & 1) != 0)crc = (crc >> 1) ^ CRC32_POLYNOMIAL;} elsecrc = crc >> 1;}}}return crc;int maiunsigned char data[] = "Hello, World!";unsigned int crc = crc32_init(;printf("CRC-32 value: %08X\n", crc ^ 0xFFFFFFFF);return 0;```以上就是CRC算法的原理及使用C语言实现的内容。
CRC校验码的原理CRC(Cyclic Redundancy Check)是一种常用的校验码,用于检测数据传输中的错误。
CRC校验码的原理是通过对数据进行计算,生成一个校验码,并将其附加到原始数据中一起传输。
接收方在收到数据后,通过重新计算校验码,并将其与接收到的校验码进行比较,以判断数据是否发生了错误。
1.选择一个固定长度的除数,通常称为生成多项式。
2.将生成多项式左移一个比特位,然后与数据的首个比特位进行“异或”操作。
结果称为“临时商”。
3.将数据向左移动一个比特位,并将上一步计算得到的临时商与下一个比特位进行“异或”操作,生成新的临时商。
4.重复上述过程,直到处理完数据的所有比特位。
5.将计算得到的临时商添加到原始数据的末尾作为校验码。
接收方收到数据后也按照相同的生成多项式重新进行CRC计算,然后将计算得到的临时商与接收到的校验码进行比较。
如果两者相等,说明数据没有发生错误;如果不相等,说明数据发生了错误。
在这种情况下,接收方可以要求发送方重新发送数据。
1.高效性:CRC校验码通常能够检测出大多数单比特和多比特的错误,很少漏掉错误。
2.易于实现:CRC校验码的计算过程可以通过硬件电路或软件算法来实现,非常简单直观。
3.不可逆性:CRC校验码不能完全确定数据中的错误位置和错误数量,而仅能检测错误。
4.灵活性:可以根据需要选择不同的生成多项式,以适应不同的数据传输环境。
需要注意的是,CRC校验码并不能检测所有的错误,特别是在数据传输距离较长、传输介质质量较差或噪声较多的情况下,仍然可能发生传输错误。
因此,在实际应用中,需要根据具体情况选择合适的校验码和纠错方法来保证数据传输的可靠性。
crc校验实例本文介绍了CRC(循环冗余校验)校验算法及其实例。
CRC是一种在数据传输过程中常用的校验方式,其基于多项式计算,通过生成冗余的比特序列来实现数据完整性的验证。
CRC可以检测出数据在传输过程中是否发生了错误或篡改。
本文将以一个简单的实例来介绍CRC校验的实现过程。
1. CRC校验算法的基本原理在传输数据时,常常会发生数据出现差错或者被人恶意篡改的情况,一旦出现这种情况,就会使得接收方的结果出错、含义歧义、甚至数据完全失效。
而CRC在数据传输期间可以帮助检测出这种变化,从而确保数据的完整性和正确性。
CRC校验可以通过一个多项式来实现。
假设数据D以二进制形式传输,那么CRC校验就是生成一个比特序列,然后与D拼接在一起,形成了一个长的二进制序列S。
然后S被除以一个特定的多项式P,并令余数为R。
根据CRC算法的定义,如果数据D正确接收到,那么R应该等于0。
也就是说,如果接收到的数据D出现错误,那么P就无法整除S,余数R也不等于0。
这样,接收方就可以根据R的值来判断数据是否正确。
2. CRC校验的实现过程下面,我们将通过一个简单的例子来介绍CRC校验的具体实现步骤。
我们假设要发送的数据为1001011,设计的多项式为1011。
因此,接收方会接收到101101010,其中最后三位000是CRC校验码。
a. 将1011(多项式)左移三位,即得到1011000。
b. 在1001011的最后加入三个0,得到1001011000c. 将1001011000除以1011,得到商10001000,余数011。
d. 将余数011拼接到1001011后面,即得到了完整的传输数据1001011011,其中最后三位为CRC校验码011。
接收方收到1001011011后,对其进行同样的计算,如果得到的余数不为0,则说明数据出现了错误。
3. CRC校验的应用场景CRC校验常常用于网络传输数据的数据完整性验证。
例如,当一个文件在Internet上传输时,发送方将计算出文件的CRC值并将其附加到文件末尾。
数据链路层计算fcs的crc算法数据链路层计算FCS(Frame Check Sequence)的CRC(Cyclic Redundancy Check)算法是一种用于检测数据传输中是否发生了错误的校验算法。
CRC算法通过在数据帧中添加一个校验字段,以便接收方可以使用相同的算法来检测出传输过程中是否发生了位错误。
1. CRC算法的基本原理是通过对数据帧进行除法运算来计算一个余数,这个余数就是校验字段的值。
计算CRC的过程可以简单地描述为:将数据帧与一个特定的多项式作除法运算,得到的余数就是CRC校验字段的值。
这个特定的多项式被称为生成多项式,通常使用的是循环冗余校验多项式(CRC polynomial)。
2. 首先,发送方和接收方必须事先约定使用相同的生成多项式。
常用的生成多项式有CRC-16和CRC-32等。
生成多项式通常表示为二进制形式,并且其最高位和最低位都为1。
3. 在发送方,数据链路层将数据帧组织成一个二进制串,并在数据帧的尾部添加一个初始的FCS值(通常为全0)。
接着,发送方将整个数据帧与生成多项式进行除法运算,计算出一个余数。
然后,将这个余数替换掉初始的FCS值,得到最终的FCS值。
4. 在接收方,当接收到数据帧后,数据链路层将数据帧与相同的生成多项式进行除法运算,得到一个余数。
如果余数为0,则表示在数据传输过程中没有发生位错误;如果余数不为0,则表示发生了位错误。
5. 接收方将计算得到的余数与接收到的FCS值进行比较。
如果两者相等,接收方则认为数据帧没有发生错误;如果两者不相等,则认为数据帧发生了错误,并且丢弃这个数据帧。
需要注意的是,CRC算法只能检测出位错误,即单个或多个位的翻转。
它无法检测出其他类型的错误,如插入、删除或替换位等。
此外,CRC算法也无法纠正错误,它只能检测出错误的存在。
总结起来,数据链路层计算FCS的CRC算法是一种用于检测数据传输中是否发生了位错误的校验算法。
crc校验原理及代码CRC(循环冗余校验)是一种错误检测技术,通过对数据进行计算和比较,来确定数据是否被改变或破坏。
它主要用于数据通信中,确保数据的完整性。
CRC校验的原理是通过生成多项式来计算发送数据的校验码,并将校验码附加到数据末尾,接收方通过再次计算校验码来验证数据的完整性。
CRC采用二进制多项式除法的方式实现。
以下是一种常见的CRC校验算法,称为CRC-32算法,它使用32位的校验码:```pythondef crc32(data):crc = 0xFFFFFFFFfor byte in data:crc ^= bytefor _ in range(8):if crc & 1:else:crc >>= 1crc ^= 0xFFFFFFFFreturn crc```利用以上的代码,可以计算给定数据的CRC-32校验码。
下面是代码的解释:1. `crc32`函数的输入参数是字符串类型的数据。
2. `crc`变量初始值为0xFFFFFFFF,是32位全1的二进制数。
3.循环遍历输入数据中的每个字节,并进行计算。
4. `crc ^= byte`将校验码与当前字节进行异或操作。
5.在每个字节的8位中,循环判断最低位是否为17.若最低位为0,则直接右移一个位置。
8.在全部字节处理完成后,将校验码与0xFFFFFFFF进行异或操作,得到最终的校验码。
CRC校验在数据通信中非常常见,特别是在网络传输和存储媒介上。
它可以帮助检测传输过程中发生的位错误,提高数据的可靠性和完整性。
需要注意的是,CRC校验是一种错误检测机制,而不是错误纠正机制。
它只能告诉我们数据是否出现错误,而无法纠正错误。
若数据被改变或破坏,则接收方可以要求重新发送数据。
CRC校验原理及步骤CRC(Cyclic Redundancy Check)校验是一种常用的错误检测方法,用于验证数据传输过程中是否存在错误。
CRC校验采用生成多项式对数据进行计算,从而生成一个固定长度的冗余校验码,将该校验码附加在数据后面进行传输,接收方利用同样的生成多项式对接收到的数据进行计算,并与接收到的校验码进行比较,如果校验码一致,则认为数据传输没有错误;如果校验码不一致,则认为数据传输存在错误。
1.选择生成多项式:在进行CRC校验前,需要选择一个生成多项式。
常用的生成多项式有:CRC-8,CRC-16,CRC-32等。
根据实际情况选择不同的生成多项式。
2.数据填充:在数据的末尾添加一组"0",长度等于生成多项式的次数加1、例如,如果选择的生成多项式为CRC-8,则在数据末尾填充一组"0",长度为9;如果选择的生成多项式为CRC-16,则在数据末尾填充一组"0",长度为173.生成校验码:利用生成多项式对填充后的数据进行除法运算,计算余数。
余数即为校验码。
通常,余数的位数为生成多项式的次数。
4.将校验码添加到数据中:将生成的校验码添加到数据末尾,并进行传输。
5.接收方计算校验码:接收方接收到数据后,利用接收到的数据和相同的生成多项式进行除法运算,计算余数。
6.比较校验码:接收方得到余数后,将其与接收到的校验码进行比较。
如果两者一致,则认为数据传输没有错误;如果两者不一致,则认为数据传输存在错误。
CRC校验的原理是利用多项式除法运算,将数据作为一个伪多项式进行计算,并得到一个余数。
由于多项式的特性,如果在数据传输过程中出现了错误,那么接收方计算得到的余数一定与发送方生成的校验码不一致。
通过比较余数和校验码,接收方可以判断数据是否传输正确。
1.简单高效:CRC校验算法计算速度快,适用于高速数据传输。
2.安全性高:CRC校验算法能够高效地检测出多种错误,包括单比特错误、双比特错误等。
crc算法java实现开头部分:CRC(Cyclic Redundancy Check)算法是一种常用的错误检测算法,用于检测数据传输过程中的错误。
它可以对发送的数据进行编码,并在接收端对接收到的数据进行解码。
CRC算法的核心思想是通过添加校验位来检测数据传输过程中的错误。
本文将介绍CRC算法的原理及其在Java中的实现。
一、CRC算法原理CRC算法的核心思想是在数据的尾部添加一组校验位,也称为CRC 码。
发送端利用原始数据和CRC生成多项式进行编码,接收端利用接收到的数据和CRC生成多项式进行解码。
如果接收到数据的CRC码与接收端生成的CRC码一致,则说明数据传输无错误;否则,数据传输过程中发生了错误。
CRC算法的实现基于多项式除法运算。
具体实现过程如下:1.发送端:(1)设定一个生成多项式G(x),长度为n+1。
多项式的系数为0或1,其中n是CRC码的长度。
(2)将原始数据进行左移n位,并在低位补零。
(3)将补零后的数据与G(x)进行模2除法运算,得到余数R(x)。
(4)将原始数据和余数R(x)拼接在一起,形成发送的数据帧。
2.接收端:(1)接收到数据帧后,将接收到的数据进行左移n位,并在低位补零。
(2)将补零后的数据与G(x)进行模2除法运算,得到余数R(x)。
(3)如果余数R(x)为0,则说明数据传输无错误;否则,说明数据传输过程中发生了错误。
二、CRC算法的Java实现以下是CRC算法在Java中的实现代码,具体实现过程为:1. CRC编码函数:```javapublic static String crcEncode(String data, String crc) { int n = crc.length() - 1; // CRC码长度int[] dataBits = new int[data.length() + n]; //补零后的数据位int[] remainder = new int[n]; //余数R(x)//将原始数据转换为整型数组for (int i = 0; i < data.length(); i++) {dataBits[i] =Integer.parseInt(String.valueOf(data.charAt(i)));}//左移n位,并在低位补零for (int i = data.length(); i < data.length() + n; i++) { dataBits[i] = 0;}//模2除法运算for (int i = 0; i < dataBits.length - n; i++) {if (dataBits[i] != 0) {for (int j = 0; j < n; j++) {dataBits[i + j] = dataBits[i + j] ^Integer.parseInt(String.valueOf(crc.charAt(j)));}}}//获取余数R(x)System.arraycopy(dataBits, dataBits.length - n, remainder, 0, n);//拼接原始数据和余数R(x)作为发送的数据帧StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(data);for (int i : remainder) {stringBuilder.append(i);}return stringBuilder.toString();}```2. CRC解码函数:```javapublic static boolean crcDecode(String data, String crc) {int n = crc.length() - 1; // CRC码长度int[] dataBits = new int[data.length()]; //接收到的数据位int[] remainder = new int[n]; //余数R(x)//将接收到的数据转换为整型数组for (int i = 0; i < data.length(); i++) {dataBits[i] =Integer.parseInt(String.valueOf(data.charAt(i)));}//左移n位,并在低位补零for (int i = 0; i < n; i++) {dataBits[i] = 0;}//模2除法运算for (int i = 0; i < dataBits.length - n; i++) { if (dataBits[i] != 0) {for (int j = 0; j < n; j++) {dataBits[i + j] = dataBits[i + j] ^Integer.parseInt(String.valueOf(crc.charAt(j)));}}}//获取余数R(x)System.arraycopy(dataBits, dataBits.length - n, remainder, 0, n);//判断接收到的数据帧是否正确for (int i : remainder) {if (i != 0) {return false;}}return true;}```以上代码实现了CRC算法的编码和解码过程。
C语言 CRC 查表算法1. 简介CRC(Cyclic Redundancy Check)是一种常用的校验算法,广泛应用于通信、存储等领域。
CRC查表算法是对CRC算法的一种优化,通过预先计算并存储CRC校验值,以提高计算效率。
本文将详细介绍C语言中的CRC查表算法,包括原理、实现步骤以及示例代码。
2. 原理CRC查表算法的核心思想是将所有可能的CRC校验值预先计算并存储在一个查表中。
在进行数据传输或校验时,只需根据输入数据逐个查表,即可得到相应的CRC校验值。
具体而言,CRC查表算法主要包括以下几个步骤:1.初始化:初始化一个256字节大小的查表数组。
2.生成查表:对于每一个可能的8位输入数据,通过一系列位运算生成对应的32位CRC校验值,并存储在查表数组中。
3.计算CRC:遍历输入数据的每个字节,利用查表数组获取相应的32位CRC校验值,并进行异或操作。
4.输出结果:最终得到32位的CRC校验值作为输出结果。
3. 实现步骤以下将详细介绍如何在C语言中实现CRC查表算法。
3.1 初始化查表数组首先,我们需要初始化一个256字节大小的查表数组,用于存储所有可能的CRC校验值。
#include <stdint.h>uint32_t crc_table[256];void init_crc_table() {uint32_t crc;for (int i = 0; i < 256; ++i) {crc = i;for (int j = 0; j < 8; ++j) {if (crc & 1)crc = (crc >> 1) ^ 0xEDB88320;elsecrc >>= 1;}crc_table[i] = crc;}}3.2 计算CRC校验值接下来,我们可以利用初始化好的查表数组来计算CRC校验值。
#include <stdint.h>uint32_t calculate_crc(const void* data, size_t size) {const uint8_t* bytes = (const uint8_t*)data;uint32_t crc = 0xFFFFFFFF;for (size_t i = 0; i < size; ++i) {uint8_t index = bytes[i] ^ (crc & 0xFF);crc = (crc >> 8) ^ crc_table[index];}return ~crc;}以上代码中,calculate_crc函数接受两个参数:data为输入数据的指针,size为输入数据的字节数。
CRC算法及工作原理CRC校验有用程序库在数据存储和数据通讯领域,为了保证数据的正确,就不得不采纳检错的手段。
在诸多检错手段中,CRC是最闻名的一种。
CRC的全称是循环冗余校验,其特点是:检错能力极强,开销小,易于用及检测实现。
从其检错能力来看,它所不能发觉的错误的几率仅为0.0047%以下。
从性能上和开销上考虑,均远远优于奇偶校验及算术和校验等方式。
因而,在数据存储和数据通讯领域,CRC无处不在:闻名的通讯协议X.25的FCS(帧检错序列)采纳的是CRC- CCITT,WinRAR、NERO、ARJ、LHA等压缩工具软件采纳的是CRC32,磁盘驱动器的读写采纳了CRC16,通用的图像存储格式GIF、TIFF等也都用CRC作为检错手段。
CRC的本质是模-2除法的余数,采纳的除数不同,CRC的类型也就不一样。
通常,CRC的除数用生成多项式来表示。
最常用的CRC码的生成多项式如表1所示。
@@10A08800.GIF;表1.最常用的CRC码及生成多项式@@因为CRC在通讯和数据处理软件中常常采纳,笔者在实际工作中对其算法举行了讨论和比较,总结并编写了一个具有最高效率的CRC通用程序库。
该程序采纳查表法计算CRC,在速度上优于普通的挺直仿照硬件的算法,可以应用于通讯和数据压缩程序。
算法通常的CRC算法在计算一个数据段的CRC值时,其CRC值是由求解每个数值的CRC值的和对CRC寄存器的值反复更新而得到的。
这样,求解 CRC的速度较慢。
通过对CRC算法的讨论,我们发觉:一个8位数据加到16位累加器中去,惟独累加器的高8位或低8位与数据相作用,其结果仅有256种可能的组合值。
因而,我们可以用查表法来代替反复的运算,这也同样适用于CRC32的计算。
本文所提供的程序库中,函数crchware是普通的16位 CRC的算法;mk-crctbl用以在内存中建立一个CRC数值表;crcupdate用以查表并更新CRC累加器的值;crcrevhware和 crcrevupdate是反序算法的两个函数;BuildCRCTable、CalculateBlockCRC32和UpdateCharacterCRC32用于CRC32的计算。
CRC校验算法CRC(Cyclic Redundancy Check)循环冗余校验是常用的数据校验方法,讲CRC算法的文章很多,之所以还要写这篇,是想换一个方法介绍CRC算法,希望能让大家更容易理解CRC 算法。
先说说什么是数据校验。
数据在传输过程(比如通过网线在两台计算机间传文件)中,由于传输信道的原因,可能会有误码现象(比如说发送数字5但接收方收到的却是6),如何发现误码呢?方法是发送额外的数据让接收方校验是否正确,这就是数据校验。
最容易想到的校验方法是和校验,就是将传送的数据(按字节方式)加起来计算出数据的总和,并将总和传给接收方,接收方收到数据后也计算总和,并与收到的总和比较看是否相同。
如果传输中出现误码,那么总和一般不会相同,从而知道有误码产生,可以让发送方再发送一遍数据。
CRC校验也是添加额外数据做为校验码,这就是CRC校验码,那么CRC校验码是如何得到的呢?非常简单,CRC校验码就是将数据除以某个固定的数(比如ANSI-CRC16中,这个数是0x18005),所得到的余数就是CRC校验码。
那这里就有一个问题,我们传送的是一串字节数据,而不是一个数据,怎么将一串数字变成一个数据呢?这也很简单,比如说2个字节B1,B2,那么对应的数就是(B1<<8)+B2;如果是3个字节B1,B2,B3,那么对应的数就是((B1<<16)+(B2<<8)+B3),比如数字是0x01,0x02, 0x03,那么对应的数字就是0x10203;依次类推。
如果字节数很多,那么对应的数就非常非常大,不过幸好CRC只需要得到余数,而不需要得到商。
从上面介绍的原理我们可以大致知道CRC校验的准确率,在CRC8中出现了误码但没发现的概率是1/256,CRC16的概率是1/65536,而CRC32的概率则是1/2^32,那已经是非常小了,所以一般在数据不多的情况下用CRC16校验就可以了,而在整个文件的校验中一般用CRC32校验。
这里还有个问题,如果被除数比除数小,那么余数就是被除数本身,比如说只要传一个字节,那么它的CRC就是它自己,为避免这种情况,在做除法之前先将它移位,使它大于除数,那么移多少位呢?这就与所选的固定除数有关了,左移位数比除数的位数少1,下面是常用标准中的除数:CRC8:多项式是X8+X5+X4+1,对应的数字是0x131,左移8位CRC12:多项式是X12+X11+X3+X2+1,对应的数字是0x180D,左移12位CCITT CRC16:多项式是X16+X12+X5+1,对应的数字是0x11021,左移16位ANSI CRC16:多项式是X16+X15+X2+1,对应的数字是0x18005,左移16位CRC32:多项式是X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1,对应数字是0x104C11DB7,左移32因此,在得到字节串对应的数字后,再将数字左移M位(比如ANSI-CRC16是左移16位),就得到了被除数。
好了,现在被除数和除数都有了,那么就要开始做除法求CRC校验码了。
CRC除法的计算过程与我们笔算除法类似,首先是被除数与除数高位对齐后,被除数减去除数,得到了差,除数再与差的最高位对齐,进行减法,然后再对齐再减,直到差比除数小,这个差就是余数。
不过和普通减法有差别的是,CRC的加(减)法是不进(借)位的,比如10减01,它的结果是11,而不是借位减法得到的01,因此,实际上CRC的加法和减法所得的结果是一样的,比如10加0 1的结果是11,10减01的结果也是11,这其实就是异或操作。
虽然说了这么多也不一定能说清楚,我们还是看一段CRC除法求余程序吧:/* 这段程序是求数据0x880000除以0x11021的余数 *//* 这段程序其实也就是求字节0x88的CRC16校验码,因为0x88左移16位是0x880000 */ unsigned short crc16_div(){unsigned long data = 0x880000;unsigned long ccitt16 = 0x11021;/* 这是比较值,被除数与它比较看是否需要减去除数注意,这里只需要与0x10000比较就可以了,而不需要与除数0x18005比较,这样可以少很多计算而且余数的范围就在0-0xFFFF之间,而不是0-0x18004之间了 */unsigned long cmp_value = 0x10000;int i;ccitt16 <<= 7; /* 左移7位,与被除数最高位对齐 */cmp_value <<= 7; /* 左移7位,与被除数最高位对齐 */while (cmp_value >= 0x10000) /* 循环直到差数比cmp_value小 */{if ((data & cmp_value) != 0) /* 最高位为1,则减去除数 */{data ^= ccitt16; /* 做CRC的减法,就是异或操作 */}else /* 最高位为0,不够减 */{/* 不作任何操作,只执行后面的移位操作 */}/* 得到了差,右移一位,与被除数下一位对齐 */ccitt16 >>= 1;cmp_value >>= 1;}/* 现在data的最低两个字节就是余数,也就是CRC校验码 */return (data & 0xFFFF);}好了,现在我们已经会计算0x88的CRC校验码了,它只是对0x880000做除法运算求余数而已,不过这只是求单字节的CRC校验码,那如果有十多个字节怎么办?我们的计算机也存不下那么大的数呀,看来我们还要对程序进行些改进,使它能对大数求除法了。
unsigned short crc16_div_2(){/* 这段程序也是求数据0x88的CRC校验码,与上一个程序crc16_div所得结果相同*//* 这里只需要直接传数据就可以,而不需要再事先移位 */unsigned short data = 0x88;/* 这里只需要2个字节0x1021,而不是0x11021,为什么不再需要最高位的1,看看代码就清楚了 */unsigned short ccitt16 = 0x1021;int i;data <<= 8;for (i=0; i<8; i++){if (data & 0x8000) /* 最高位为1,减去除数 */{data <<= 1; /* 将最高位的1移出,剩下的数与0x1021(而不是0x11021)异或,这是因为最高位的1与0x11021的最高位1异或后为0 */data ^= ccitt16;}else /* 最高位为0,不需要减去除数 */{data <<= 1; /* 直接移位 */}}return data;}现在对单字节0x88求CRC16,我们只需要两字节short型的整数就行了,而不需要象以前必须用long型0x880000,其实不管多少字节,只用short型就能够计算它的CRC16。
下面说说怎么求多字节的样验码:当我们求得一个字节(比如0x88)的CRC校验码后,如果这时又有一个字节(比如0x23)加入,需要求校验码,该怎么办呢?以前得到的是0x880000除以0x11021的余数,但现在需要得到的是0x88230000除以0x11021的余数,以前求得的校验码是不是白费了?不是的,因为当我们得到0x880000除以0x11021的余数(这里余数是0x1080)后,需要求0x88230000除以0x11021的余数,只要将原来的余数0x1080左移8位除以0x11021就得到了0x98000000除以0x11021的余数<0x108000除以0x11021的余数>(想一想为什么),再加上0x230000除以0x11021的余数。
这其实就是求0x108000+0x230000除以0x11021的余数.。
因此根据这个方法,我们就可以写出求多个字节的CRC算法:/* 这段代码是求ccitt-crc16的算法参数:data:字节数据crc:原来数据求得的crc校验码返回值:数据的ccitt-crc16校验码*/unsigned short crc16_ccitt(unsigned char data, unsigned short crc){unsigned short ccitt16 = 0x1021;int i;crc ^= (data<<8); /* 新的数据与将原来的余数(就是crc)相加(加法就是异或操作) *//* 求数据的CRC校验码 */for (i=0; i<8; i++){if (crc & 0x8000) /* 最高位为1,减去除数 */{crc <<= 1;crc ^= ccitt16;}else /* 最高位为0,不需要减去除数 */{crc <<= 1; /* 直接移位 */}}return crc;}/* 这是个主程序,表示如何计算5个字节的CRC */void main(){int i;unsigned short crc;char data[5] = { 0x71, 0x88, 0x93, 0xa5, 0x13 }; /* 计算这5个数据的CRC校验码 */crc = 0;for (i=0; i<5; i++){crc = crc16_ccitt(data[i], crc);}printf("crc is %x", crc);}好了,讲到这里CRC算法已经全部介绍完了。
什么,讲完了?不对呀,我怎么记得C RC程序都有个数组叫CRC表什么的,你这里怎么没有?呵呵,其实使用CRC表是为了节省一些运算时间,事先将算好的CRC保存在数组里,省得临时再计算,它保存的是0到0xff的CRC码,下面我们来自己生成一个CRC表:unsigned short CRC16_CCITT_TABLE[256];void init_crc16_ccitt_table(){int i;for (i=0; i<256; i++){CRC16_CCITT_TABLE[i] = crc16_ccitt(i, 0);}}上面只是一个字节的CRC表,那多个字节的CRC如何计算呢?与前面求多字节的CRC 方法差不多,它的代码如下:/* 这段代码是查表求ccitt-crc16的算法,它与前面的程序crc16_ccitt所得到的结果一样参数:data:字节数据crc:原来数据求得的crc校验码返回值:数据的ccitt-crc16校验码unsigned short crc16_ccitt_2(unsigned char data, unsigned short crc){unsigned char c;c = crc >> 8; /* c的值为crc的高8位 */crc <<= 8; /* crc现在的值变为低8位左移8位 */crc ^= CRC16_CCITT_TABLE[data ^ c];return crc;}最后要说的是CRC的正序和反转问题,比如前面ccitt-crc16的正序是0x1021,如果是反转就是0x8408(就是将0x1021倒过来低位变高位)为什么要反转?这是因为数据传输可能是先传低位再传高位(比如串口就是低位在前高位在后)。