CRC校验和C语言实现

1.参考资料

  • 参考
    • A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS
    • 写给嵌入式程序员的循环冗余校验(CRC)算法入门引导
    • CRC (循环冗余校验)
    • 模2运算
  • 前言
    本文首先参考了链接2的博客,上面讲的很详细,从奇偶校验、累加和校验、模2运算到CRC校验和优化。并提供了相应的参考链接,很值得参考。如果要深入理解算法的实现原理需要参考链接1

2.简单的crc程序

  • 参考

    • c语言实现CRC校验和
    • Calculating 16-bit CRCs (CRC-16)
  • 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 
    
    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 
      
      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-32
    • A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS
  • 代码
    下面的代码总共使用了四种产生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 
    #include 
    
    
    // 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 crcmask;
    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);
    		crc&= crcmask;
    		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;
    	crc&= crcmask;
    
    	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;
    	crc&= crcmask;
    
    	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;
    	crc&= crcmask;
    
    	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;
    	crc&= crcmask;
    
    	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
    
    	crcmask = ((((unsigned long)1<<(order-1))-1)<<1)|1;
    	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;
    		}
    		crc&= crcmask;
    		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);
    }
    

你可能感兴趣的:(算法)