CRC校验和C语言实现

1.参考资料

• 参考
• 前言
本文首先参考了`链接2`的博客，上面讲的很详细，从奇偶校验、累加和校验、模2运算到CRC校验和优化。并提供了相应的参考链接，很值得参考。如果要深入理解算法的实现原理需要参考`链接1`

2.简单的crc程序

• 参考

• crc16代码

``````/* * download from : https://www.cnblogs.com/youthshouting/p/4388232.html * another link : http://mdfs.net/Info/Comp/Comms/CRC16.htm * another link : https://blog.csdn.net/liyuanbhu/article/details/7882789 */

#include <stdio.h>

int CalCrc(int crc, const char *buf, int len)
{
unsigned int byte;
unsigned char k;
unsigned short ACC,TOPBIT;
// unsigned short remainder = 0x0000;
unsigned short remainder = crc;
TOPBIT = 0x8000;
for (byte = 0; byte < len; ++byte)
{
ACC = buf[byte];
remainder ^= (ACC <<8);
for (k = 8; k > 0; --k)
{
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^0x8005;
}
else
{
remainder = (remainder << 1);
}
}
}
remainder=remainder^0x0000;
return remainder;
}
int main(int argc, char* argv[])
{
char buffer[22] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x02, 0x03, 0x04};
unsigned short crc = CalCrc(0, buffer, 20);//计算得到的16位CRC校验码
buffer[21] = (char)crc;//取校验码的低八位
buffer[20] = (char)(crc >> 8);//取校验码的高八位
//接收方在接收到buffer中的数据时，代入CalCrc进行计算，若result的值为0，则说明数据传输过程无误
unsigned short result = CalCrc(0, buffer, 22);
if (result == 0){
printf("crc result is right\n");
}
return 0;
}

``````

3.crc16查表法

• 参考
• Programming Embedded Systems in C and C++, section 6
• 代码
• crc.h

``````/* * copy from : https://blog.csdn.net/liyuanbhu/article/details/7882789 * refer from book : Programming Embedded Systems in C and C++, section 6 */

/* 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

``````/* * copy from : https://blog.csdn.net/liyuanbhu/article/details/7882789 * refer from book : Programming Embedded Systems in C and C++, section 6 */

/* *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() */

``````
• main.c

``````/* * copy from : https://blog.csdn.net/liyuanbhu/article/details/7882789 * refer from book : Programming Embedded Systems in C and C++, section 6 */

#include "crc.h"
#include <stdio.h>

int main(int argc, char* argv[])
{
char buffer[22] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x02, 0x03, 0x04};
crcInit();
width_t crc = crcCompute(buffer, 20);
//unsigned short crc = CalCrc(0, buffer, 20);//计算得到的16位CRC校验码
buffer[21] = (char)crc;//取校验码的低八位
buffer[20] = (char)(crc >> 8);//取校验码的高八位
//接收方在接收到buffer中的数据时，代入CalCrc进行计算，若result的值为0，则说明数据传输过程无误
width_t result = crcCompute(buffer, 22);
//unsigned short result = CalCrc(0, buffer, 22);
if (result == 0){
printf("crc result is right\n");
}
return 0;
}
``````

4.crc32

• 参考

• 代码
下面的代码总共使用了四种产生crc校验码的方法

``````/* * download from : http://www.zorc.breitbandkatze.de/crctester.c * a link is : http://www.zorc.breitbandkatze.de/crc.html */

// ----------------------------------------------------------------------------
// CRC tester v1.3 written on 4th of February 2003 by Sven Reifegerste (zorc/reflex)
// This is the complete compilable C program, consisting only of this .c file.
// No guarantee for any mistakes.
//
// changes to CRC tester v1.2:
//
// - remove unneccessary (!(polynom&1)) test for invalid polynoms
// (now also XMODEM parameters 0x8408 work in c-code as they should)
//
// changes to CRC tester v1.1:
//
// - include an crc&0crcmask after converting non-direct to direct initial
// value to avoid overflow
//
// changes to CRC tester v1.0:
//
// - most int's were replaced by unsigned long's to allow longer input strings
// and avoid overflows and unnecessary type-casting's
// ----------------------------------------------------------------------------

// includes:

#include <string.h>
#include <stdio.h>

// CRC parameters (default values are for CRC-32):

const int order = 32;
const unsigned long polynom = 0x4c11db7;
const int direct = 1;
const unsigned long crcinit = 0xffffffff;
const unsigned long crcxor = 0xffffffff;
const int refin = 1;
const int refout = 1;

// 'order' [1..32] is the CRC polynom order, counted without the leading '1' bit
// 'polynom' is the CRC polynom without leading '1' bit
// 'direct' [0,1] specifies the kind of algorithm: 1=direct, no augmented zero bits
// 'crcinit' is the initial CRC value belonging to that algorithm
// 'crcxor' is the final XOR value
// 'refin' [0,1] specifies if a data byte is reflected before processing (UART) or not
// 'refout' [0,1] specifies if the CRC will be reflected before XOR

// Data character string

const unsigned char string[] = {"123456789"};

// internal global values:

unsigned long crchighbit;
unsigned long crcinit_direct;
unsigned long crcinit_nondirect;
unsigned long crctab[256];

// subroutines

unsigned long reflect (unsigned long crc, int bitnum) {

// reflects the lower 'bitnum' bits of 'crc'

unsigned long i, j=1, crcout=0;

for (i=(unsigned long)1<<(bitnum-1); i; i>>=1) {
if (crc & i) crcout|=j;
j<<= 1;
}
return (crcout);
}

void generate_crc_table() {

// make CRC lookup table used by table algorithms

int i, j;
unsigned long bit, crc;

for (i=0; i<256; i++) {

crc=(unsigned long)i;
if (refin) crc=reflect(crc, 8);
crc<<= order-8;

for (j=0; j<8; j++) {

bit = crc & crchighbit;
crc<<= 1;
if (bit) crc^= polynom;
}

if (refin) crc = reflect(crc, order);
crctab[i]= crc;
}
}

unsigned long crctablefast (unsigned char* p, unsigned long len) {

// fast lookup table algorithm without augmented zero bytes, e.g. used in pkzip.
// only usable with polynom orders of 8, 16, 24 or 32.

unsigned long crc = crcinit_direct;

if (refin) crc = reflect(crc, order);

if (!refin) while (len--) crc = (crc << 8) ^ crctab[ ((crc >> (order-8)) & 0xff) ^ *p++];
else while (len--) crc = (crc >> 8) ^ crctab[ (crc & 0xff) ^ *p++];

if (refout^refin) crc = reflect(crc, order);
crc^= crcxor;

return(crc);
}

unsigned long crctable (unsigned char* p, unsigned long len) {

// normal lookup table algorithm with augmented zero bytes.
// only usable with polynom orders of 8, 16, 24 or 32.

unsigned long crc = crcinit_nondirect;

if (refin) crc = reflect(crc, order);

if (!refin) while (len--) crc = ((crc << 8) | *p++) ^ crctab[ (crc >> (order-8))  & 0xff];
else while (len--) crc = ((crc >> 8) | (*p++ << (order-8))) ^ crctab[ crc & 0xff];

if (!refin) while (++len < order/8) crc = (crc << 8) ^ crctab[ (crc >> (order-8))  & 0xff];
else while (++len < order/8) crc = (crc >> 8) ^ crctab[crc & 0xff];

if (refout^refin) crc = reflect(crc, order);
crc^= crcxor;

return(crc);
}

unsigned long crcbitbybit(unsigned char* p, unsigned long len) {

// bit by bit algorithm with augmented zero bytes.
// does not use lookup table, suited for polynom orders between 1...32.

unsigned long i, j, c, bit;
unsigned long crc = crcinit_nondirect;

for (i=0; i<len; i++) {

c = (unsigned long)*p++;
if (refin) c = reflect(c, 8);

for (j=0x80; j; j>>=1) {

bit = crc & crchighbit;
crc<<= 1;
if (c & j) crc|= 1;
if (bit) crc^= polynom;
}
}

for (i=0; i<order; i++) {

bit = crc & crchighbit;
crc<<= 1;
if (bit) crc^= polynom;
}

if (refout) crc=reflect(crc, order);
crc^= crcxor;

return(crc);
}

unsigned long crcbitbybitfast(unsigned char* p, unsigned long len) {

// fast bit by bit algorithm without augmented zero bytes.
// does not use lookup table, suited for polynom orders between 1...32.

unsigned long i, j, c, bit;
unsigned long crc = crcinit_direct;

for (i=0; i<len; i++) {

c = (unsigned long)*p++;
if (refin) c = reflect(c, 8);

for (j=0x80; j; j>>=1) {

bit = crc & crchighbit;
crc<<= 1;
if (c & j) bit^= crchighbit;
if (bit) crc^= polynom;
}
}

if (refout) crc=reflect(crc, order);
crc^= crcxor;

return(crc);
}

int main() {

// test program for checking four different CRC computing types that are:
// crcbit(), crcbitfast(), crctable() and crctablefast(), see above.
// parameters are at the top of this program.
// Result will be printed on the console.

int i;
unsigned long bit, crc;

// at first, compute constant bit masks for whole CRC and CRC high bit

crchighbit = (unsigned long)1<<(order-1);

// check parameters

if (order < 1 || order > 32) {
printf("ERROR, invalid order, it must be between 1..32.\n");
return(0);
}

if (polynom != (polynom & crcmask)) {
printf("ERROR, invalid polynom.\n");
return(0);
}

if (crcinit != (crcinit & crcmask)) {
printf("ERROR, invalid crcinit.\n");
return(0);
}

if (crcxor != (crcxor & crcmask)) {
printf("ERROR, invalid crcxor.\n");
return(0);
}

// generate lookup table

generate_crc_table();

// compute missing initial CRC value

if (!direct) {

crcinit_nondirect = crcinit;
crc = crcinit;
for (i=0; i<order; i++) {

bit = crc & crchighbit;
crc<<= 1;
if (bit) crc^= polynom;
}
crcinit_direct = crc;
}

else {

crcinit_direct = crcinit;
crc = crcinit;
for (i=0; i<order; i++) {

bit = crc & 1;
if (bit) crc^= polynom;
crc >>= 1;
if (bit) crc|= crchighbit;
}
crcinit_nondirect = crc;
}

// call CRC algorithms using the CRC parameters above and print result to the console

printf("\n");
printf("CRC tester v1.1 written on 13/01/2003 by Sven Reifegerste (zorc/reflex)\n");
printf("-----------------------------------------------------------------------\n");
printf("\n");
printf("Parameters:\n");
printf("\n");
printf(" polynom : 0x%x\n", polynom);
printf(" order : %d\n", order);
printf(" crcinit : 0x%x direct, 0x%x nondirect\n", crcinit_direct, crcinit_nondirect);
printf(" crcxor : 0x%x\n", crcxor);
printf(" refin : %d\n", refin);
printf(" refout : %d\n", refout);
printf("\n");
printf(" data string : '%s' (%d bytes)\n", string, strlen(string));
printf("\n");
printf("Results:\n");
printf("\n");

printf(" crc bit by bit : 0x%x\n", crcbitbybit((unsigned char *)string, strlen(string)));
printf(" crc bit by bit fast : 0x%x\n", crcbitbybitfast((unsigned char *)string, strlen(string)));
if (!(order&7)) printf(" crc table : 0x%x\n", crctable((unsigned char *)string, strlen(string)));
if (!(order&7)) printf(" crc table fast : 0x%x\n", crctablefast((unsigned char *)string, strlen(string)));

return(0);
}
``````