我正在阅读有关CRC的信息,我在CRC catalogue和CRC-CCITT上发现了这篇文章。
我根据第二个链接实现了MyCrc16
(参见下面的代码)。
其中,按顺序依次取字节,按顺序将它们逐个移位到(初始)CRC中,然后用多项式进行异或运算得到余数,再加上最后的扩充。
现在......我还有一些预先存在的CRC16实现(OtherCrc16
),根据目录是CRC-16 / CCITT-FALSE。
我不明白为什么OtherCrc16
有效?因为输入的第一个字节以及之后的所有其余字节与(初始)CRC进行异或,而不是像其他实现那样附加到它。当迭代比特时,它没有考虑第一个算法认为“将输入转换为CRC”的内容,而是在必要时只用多项式进行异或。
我错过了XOR操作的一些属性吗? 在我看来,这两个算法应该具有相同的输出(当然不考虑第一个算法的扩充),但它们没有。
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
uint16_t MyCrc16(const unsigned char *data, int length, uint16_t poly, uint16_t crc)
{
for(int byte=0; byte<length; ++byte)
{
for(int bit=7; bit>=0; --bit)
{
bool doXor = false;
if(crc & 0x8000)
{
doXor = true;
}
crc <<= 1;
if(data[byte] & (1 << bit))
{
crc += 1;
}
if(doXor)
{
crc ^= poly;
}
}
}
//augument the crc with 0s
for(int i=0; i<16; i++)
{
bool doXor = false;
if(crc & 0x8000)
{
doXor = true;
}
crc = crc << 1;
if(doXor)
{
crc ^= poly;
}
}
return crc;
}
uint16_t OtherCrc16(const unsigned char *data, int length, uint16_t poly, uint16_t crc)
{
for(int i=0; i<length; i++)
{
crc = crc ^ (data[i] << 8);
for (int bit = 0; bit< 8; bit++)
{
bool doXor = false;
if(crc & 0x8000)
{
doXor = true;
}
crc <<=1;
if(doXor)
{
crc ^= poly;
}
}
}
return crc;
}
int main(void) {
// your code goes here
uint16_t poly = 0x1021;
unsigned char c[] = "123456789";
printf("My CRC = %04x\n", MyCrc16(c, 9, poly, 0xffff));
printf("Other CRC = %04x\n", OtherCrc16(c, 9, poly, 0xffff));
return 0;
}
PS: 可执行代码:http://ideone.com/mKuQqQ
答案 0 :(得分:0)
如果CRC的初始值为零,则两种方法都会产生相同的CRC。但是,如果CRC的初始值不为零,则MyCrc16在该初始值开始包含任何数据位之前将其循环16次,就好像它以16个零位作为数据前缀。对于非零的初始CRC,MyCrc16需要将初始值反转循环16次,以便在将初始值循环循环16次之后,该值与OtherCrc16中使用的初始值相同。对于初始值为0xffff,将其反向循环16次将产生0x84cf。评论中的以下更改将导致两种方法产生相同的CRC:
printf("My CRC = %04x\n", MyCrc16(c, 9, poly, 0x84cf)); /* change to 0x84cf */
printf("Other CRC = %04x\n", OtherCrc16(c, 9, poly, 0xffff));