一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术, 主要用来检测或校验数据传输或者保存后可能出现的错误。
它是利用除法及余数的原理来作错误侦测的。
CRC参数模型
一个完整的CRC参数模型应该包含以下信息:WIDTH,POLY,INIT,REFIN,REFOUT,XOROUT。
- NAME:参数模型名称。
- WIDTH:宽度,即生成的CRC数据位宽,如CRC-8,生成的CRC为8位
- POLY:十六进制多项式,省略最高位1,如 x8 + x2 + x + 1,二进制为1 0000 0111,省略最高位1,转换为十六进制为0x07。
- INIT:CRC初始值,和WIDTH位宽一致。
- REFIN:true或false,在进行计算之前,原始数据(每个字节)是否翻转,如原始数据:0x34 = 0011 0100,如果REFIN为true,进行翻转之后为0010 1100 = 0x2c
- REFOUT:true或false,运算完成之后,得到的CRC值(整个数据)是否进行翻转,如计算得到的CRC值:0x97 = 1001 0111,如果REFOUT为true,进行翻转之后为11101001 = 0xE9。
- XOROUT:计算结果与此参数进行异或运算后得到最终的CRC值,和WIDTH位宽一致。
CRC计算
问:原始数据:0x34,使用CRC-8/MAXIN参数模型,求CRC值?
根据上表,CRC-8/MAXIN参数模型参数如下:
POLY = 0x31 = 0011 0001(最高位1已经省略)
INIT = 0x00
XOROUT = 0x00
REFIN = TRUE
REFOUT = TRUE
计算过程
- 原始数据 = 0x34 = 0011 0100,多项式 = 0x31 = 1 0011 0001
- INIT = 00,原始数据高8位和初始值进行异或运算保持不变。
- REFIN为TRUE,需要先对原始数据进行翻转:0011 0100 > 0010 1100
- 原始数据左移8位,即后面补8个0:0010 1100 0000 0000
- 把处理之后的数据和多项式进行模2除法,求得余数:
原始数据:0010 1100 0000 0000 = 10 1100 0000 0000
多项式:1 0011 0001
模2除法取余数低8位:1111 1011
- 与XOROUT进行异或,1111 1011 xor 0000 0000 = 1111 1011
- 因为REFOUT为TRUE,对结果进行翻转得到最终的CRC-8值:1101 1111 = 0xDF
- 数据+CRC:0011 0100 1101 1111 = 34DF,相当于原始数据左移8位+余数。
C source code
GitHub - whik/crc-lib-c: 基于C语言的CRC校验库,包括常用的21个CRC参数模型实现基于C语言的CRC校验库,包括常用的21个CRC参数模型实现. Contribute to whik/crc-lib-c development by creating an account on GitHub.https://github.com/whik/crc-lib-c【注】如REFIN/REFOUT 为 TRUE,即需要对数据进行反转时,可以从数据的最低bit开始计算,则可避免反转操作。
/****************************************************************************** * Name: CRC-32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 * Poly: 0x4C11DB7 * Init: 0xFFFFFFF * Refin: True * Refout: True * Xorout: 0xFFFFFFF * Alias: CRC_32/ADCCP * Use: WinRAR,ect. *****************************************************************************/ uint32_t crc32(uint8_t *data, uint16_t length) { uint8_t i; uint32_t crc = 0xffffffff; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) crc = (crc >> 1) ^ 0xEDB88320;// 0xEDB88320= reverse 0x04C11DB7 else crc = (crc >> 1); } } return ~crc; } | /********************************************************************* * * Function: crc32() * * Description: Compute the CRC of a given message. * * Notes: * * Returns: The CRC of the message. * *********************************************************************/ uint32_t crc32(const void *data, int nBytes) { crc remainder = INITIAL_REMAINDER; int byte; unsigned char bit; unsigned char const *message = data; /* * Perform modulo-2 division, a byte at a time. */ for (byte = 0; byte < nBytes; ++byte) { /* * Bring the next byte into the remainder. */ remainder ^= (REFLECT_DATA(message[byte]) << (WIDTH - 8)); /* * Perform modulo-2 division, a bit at a time. */ for (bit = 8; bit > 0; --bit) { /* * Try to divide the current data bit. */ if (remainder & TOPBIT) { remainder = (remainder << 1) ^ POLYNOMIAL; } else { remainder = (remainder << 1); } } } /* * The final remainder is the CRC result. */ return (REFLECT_REMAINDER(remainder) ^ FINAL_XOR_VALUE); } /* crc32() */ |
在线计算工具
参考资料