CRC比较和类似算法之间的区别

时间:2016-11-28 22:57:02

标签: c algorithm crc16

我正在阅读有关CRC的信息,我在CRC catalogueCRC-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

1 个答案:

答案 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));