CRC校验原理及代码实现(一)

网上的有关CRC的原理和代码实现的文章,数不胜数,但比较全的好像还没看到;此文是集百家之智慧,加之自己的使用经验和理解汇聚此文,让你快速理解和使用CRC,当然不足之处欢迎评论区吐槽。

1. CRC是什么 ?

循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。

---- 来自百度百科

哦,他是生成一段数据包校验码的一种算法,用于发送和接收方的数据校验,减少数据帧出错概率;

那他的实现算法是什么样的,有统一的官方标准吗,还是有百花齐放? 有,有官方的算法标准

2. CRC标准算法

官方的标准算法链接还没找到,这里是汇聚网友的智慧,大家发的几乎都是这套,公认的应该就没错了,有找到的欢迎评论区留言。

CRC标准算法模型的几个参数:

  • 宽度(width):校验码所占的比特位,比如我们常说的CRC16,宽度就是16;

  • 多项式(poly):参与计算的一个常量数值;

  • 初始值(init):开始计算时,CRC的预设数值;

  • 是否翻转(ref):输入或输出数据的比特位顺序是否翻转,比如0x55翻转为0xAA;

  • XOROUT:常量数值,输出结果与此数值异或得到最终结果,为0时,无需异或;

可见如果发送数据和接收数据是两个代码组件,不同的工程师在写,CRC的算法模型参数还要沟通使用一致哦

常见CRC标准算法模型参数表

名称 多项式(poly) 初始值(init) 是否翻转(ref) XOROUT
CRC16_CCITT X^16+X^12+X^5+1 (0x1021) 0x0000 true 0x0000
CRC16_CCITT_FALSE X^16+X^12+X^5+1 (0x1021) 0xFFFF false 0x0000
CRC16_MODBUS X^16+X^15+X^2+1 (0x8005) 0xFFFF true 0x0000
CRC16_XMODEM X^16+X^12+X^5+1 (0x1021) 0x0000 false 0x0000

这里的多项式X^16+X^12+X^5+1怎么转成0x1021的呢,(1 << 16) | (1 << 12) | (1 << 5) | 1 = 0x1021

3. CRC16标准算法 C代码实现

这里说明一种通用统一的实现方法,所有的算法模型按上述参数都可以使用此函数实现;

​
static void invert_uint8(unsigned char *dstBuf, unsigned char *srcBuf)
{
    unsigned char i,tmp = 0;
    for ( i = 0; i < 8; i++){
        if (srcBuf[0] & (1 << i)){
            tmp |= 1 << (7-i);
        }
    }
    *dstBuf = tmp;
}
​
static void invert_uint16(unsigned short *dstBuf, unsigned short *srcBuf)
{
    unsigned short i,tmp = 0;
    for ( i = 0; i < 16; i++){
        if (srcBuf[0] & (1 << i)){
            tmp |= 1 << (15-i);
        }
    }
    *dstBuf = tmp;
}
​
/*****************************************************************
 * @Function: iot_calculate_crc16
 * @Description: 计算CRC16值的算法实现,适配所有CRC16的协议
 * @Param: ref_flag,数据位序翻转,true-低位在前,高位在后
 * @Return: void
 *****************************************************************/
unsigned short iot_calculate_crc16(unsigned char *data,unsigned int size,const unsigned short crc_poly,unsigned short init_value,unsigned char ref_flag)
{    
    unsigned short crc_reg = init_value,tmp = 0;
    unsigned char j,byte = 0;
    
    while (size--){
        byte = *(data++);
        if (ref_flag)
            invert_uint8(&byte,&byte);
        crc_reg ^= byte << 8;
        for ( j = 0; j < 8; j++){
            tmp = crc_reg & 0x8000;
            crc_reg <<= 1;
            if (tmp)
                crc_reg ^= crc_poly;
        }
    }
    
    if (ref_flag)
        invert_uint16(&crc_reg,&crc_reg);
    
    // 这里XOROUT数值固定为0x0000
    return crc_reg;  // 等价于 return (crc_reg ^ 0X0000);
}
// 按CRC所用协议直接调用如下宏函数即可,这里只列出部分常用的
\#define IOT_CRC16_CCITT_FALSE(data,size) iot_calculate_crc16(data,size,0x1021,0xFFFF,0)
\#define IOT_CRC16_CCITT(data,size) iot_calculate_crc16(data,size,0x1021,0x0000,1)
\#define IOT_CRC16_MODBUS(data,size) iot_calculate_crc16(data,size,0x8005,0xFFFF,1)
\#define IOT_CRC16_XMODEM(data,size) iot_calculate_crc16(data,size,0x1021,0x0000,0)
\#define IOT_CRC16_YMODEM(data,size) iot_calculate_crc16(data,size,0x1021,0x0000,0)

看了上述CRC16的,CRC32的实现应该也就很清晰了吧

好了,本文就写到这里,希望对你的项目有些帮助,后面(二)将分享CRC校验码的碰撞概率如何,分享之前大可以放心使用,比和校验的碰撞概率肯定低得多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章