http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html#ch6
CRC(循环冗余校验)是一种检测数据不一致性的校验算法,例如在数据传输过程中出现的位错误。由 CRC 计算得出的校验和附加到数据上,以帮助接收方检测此类错误。
CRC 基于除法。实际输入数据被解释为一个长的二进制位流(被除数),它被另一个固定的二进制数(除数)所除。这个除法的余数就是校验和。二进制数字(被除数和除数)不像普通整型值那样处理,而是作为二元多项式来处理,其中实际位用作系数。
例如输入数据 0x25 = 0010 0101 被视为 .
CRC-n
使用具有 (n+1)
位的固定定义生成多项式// 输出数据是 byte 0xC2 = b1100 0010
// 生成多项式,即除数为 b10001 1101(除数9位,因此是CRC-8,添加8个 0bits 到输入数据末尾)
// 将除数的前导“1”与被除数的第一个“1”对齐,逐步进行除法运算,但是对每个位使用XOR操作:
1100001000000000
100011101
---------
010011001
100011101
---------
000101111
100011101 (*)
---------
001100101
100011101
---------
010001001
100011101
---------
000001111 = 0x0F
余数是 CRC 值,它与输入数据一起传输到接收器。常见的做法是,直接将 CRC 值附加到实际数据末尾。然后接收器在整个数据上(包括已附加了 CRC 值的输入)计算 CRC:如果 CRC 值为 0,则很可能在传输过程中没有发生位错误。
通过手动模拟的过程,可以很容易地通过移位寄存器的方式逐步计算出最后的余数。
MSB
是 1
,则使用生成多项式对寄存器值进行异或操作;生成多项式的最高位是 1,并且在除法过程中会将生成多项式的最高位 1 与被除数的下一个最高位 1 对齐,异或为 0,所以运算过程可以忽略生成多项式的最高位 1,例如 9 位的 b100011101 只需要使用 0x1D 进行运算。
// 按照手动除法的模拟
b1 0
b2 0
b3 0
......
#include <cstdint>
uint8_t Compute_CRC8_Simple(const unsigned char* bytes, size_t length)
{
const uint8_t generator = 0x1D; // b100011101 = 0x1D
uint8_t crc = 0; /* first byte can be 'xored' in */
for (size_t j = 0; j < length; j++)
{
crc ^= bytes[j]; /* XOR-in the next input byte */
for (int i = 0; i < 8; i++)
{
if ((crc & 0x80) != 0)
crc = (crc << 1) ^ generator;
else
crc <<= 1;
}
}
return crc;
}
生成多项式取 33-bit,这里使用 0x04C11DB7(省略最高位的 1)。
#include <cstdint>
uint32_t Compute_CRC32_Simple(const unsigned char* bytes, size_t length){
const uint32_t polynomial = 0x04C11DB7; /* divisor is 32bit */
uint32_t crc = 0; /* CRC value is 32bit */
for (size_t j = 0; j < length; j++){
crc ^= (uint32_t)(bytes[j] << 24); /* move byte into MSB of 32bit CRC */
for (int i = 0; i < 8; i++){
if ((crc & 0x80000000) != 0) /* test for MSB = bit 31 */
crc = (uint32_t)((crc << 1) ^ polynomial);
else
crc <<= 1;
}
}
return crc;
}
本文链接: Understanding and implementing CRC
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
发布日期: 2023-05-01
最新构建: 2024-12-26
欢迎任何与文章内容相关并保持尊重的评论😊 !