C++ 如何配置CRC表的计算

C++ 如何配置CRC表的计算,c++,crc,crc16,C++,Crc,Crc16,有很多CRC计算的例子。具有位移位的简单实现,使用预先计算的表更高效。但是除了多项式之外,CRC还有很多参数影响计算。您可以在此处评估这些参数: 这些参数是 CRC初始值 输入数据的反射 输出数据的反映 CRC的最终异或值 对于一些“标准”CRC算法,这些参数定义良好,如CRC-16(CCITT)。但有些实现使用不同的参数 我的实现必须与带有CCITT多项式(x16+x12+x5+1)的CRC16兼容。但必须反映数据字节和最终CRC。我已经在计算方法中实现了这些反射。但这很耗时。为了获得最佳

有很多CRC计算的例子。具有位移位的简单实现,使用预先计算的表更高效。但是除了多项式之外,CRC还有很多参数影响计算。您可以在此处评估这些参数:

这些参数是

  • CRC初始值
  • 输入数据的反射
  • 输出数据的反映
  • CRC的最终异或值
对于一些“标准”CRC算法,这些参数定义良好,如CRC-16(CCITT)。但有些实现使用不同的参数

我的实现必须与带有CCITT多项式(x16+x12+x5+1)的CRC16兼容。但必须反映数据字节和最终CRC。我已经在计算方法中实现了这些反射。但这很耗时。为了获得最佳性能,必须将其从计算中删除

如何在初始化方法中计算CRC的反射参数

编辑:我应该如何单独控制每个参数?我想了解
Init
函数实际上是如何工作的,以及所有参数是如何实现的

typedef unsigned char uint8_t;
typedef unsigned short crc;

crc  crcTable[256];
#define WIDTH  (8 * sizeof(crc))
#define TOPBIT (1 << (WIDTH - 1))
#define POLYNOMIAL 0x1021

template<typename t>
t reflect(t v)
{
    t r = 0;

    for (int i = 0; i < (8 * sizeof v); ++i)
    {
        r <<= 1;
        r |= v&1;
        v >>= 1;
    }

    return r;
}

void Init()
{
    crc  remainder;

    for (int dividend = 0; dividend < 256; ++dividend)
    {
        remainder = dividend << (WIDTH - 8);

        for (uint8_t bit = 8; bit > 0; --bit)
        {
            if (remainder & TOPBIT)
                remainder = (remainder << 1) ^ POLYNOMIAL;
            else
                remainder = (remainder << 1);
        }

        crcTable[dividend] = remainder;
    }
}

crc Calculate(const uint8_t *message, int nBytes, crc wOldCRC)
{
    uint8_t data;
    crc remainder = wOldCRC;

    for (int byte = 0; byte < nBytes; ++byte)
    {
        data = reflect(message[byte]) ^ (remainder >> (WIDTH - 8));
        remainder = crcTable[data] ^ (remainder << 8);
    }

    return reflect(remainder);
}

int main()
{
    crc expected = 0x6f91;
    uint8_t pattern[] = "123456789";

    Init();
    crc result = Calculate(pattern, 9, 0xFFFF);

    if (result != expected)
    {
        // this output is not relevant to the question, despite C++ tag
        printf("CRC 0x%04x wrong, expected 0x%04x\n", result, expected);
    }
}
typedef无符号字符uint8\t;
typedef无符号短crc;
crc crcTable[256];
#定义宽度(8*sizeof(crc))

#定义TOPBIT(1而不是反映输入的数据、输入的CRC和输出的CRC,您只需反映多项式和运算。在编写代码时,您只需要这样做一次。反映的多项式是
0x8408

typedef unsigned char uint8_t;
typedef unsigned short crc;

crc  crcTable[256];
#define POLYNOMIAL 0x8408

void Init()
{
    crc  remainder;

    for (int dividend = 0; dividend < 256; ++dividend)
    {
        remainder = dividend;

        for (uint8_t bit = 8; bit > 0; --bit)
        {
            if (remainder & 1)
                remainder = (remainder >> 1) ^ POLYNOMIAL;
            else
                remainder = (remainder >> 1);
        }

        crcTable[dividend] = remainder;
    }
}

crc Calculate(const uint8_t *message, int nBytes, crc wOldCRC)
{
    uint8_t data;
    crc remainder = wOldCRC;

    for (int byte = 0; byte < nBytes; ++byte)
    {
        data = message[byte] ^ remainder;
        remainder = crcTable[data] ^ (remainder >> 8);
    }

    return remainder;
}

int main()
{
    crc expected = 0x6f91;
    uint8_t pattern[] = "123456789";

    Init();
    crc result = Calculate(pattern, 9, 0xFFFF);

    if (result != expected)
    {
        // this output is not relevant to the question, despite C++ tag
        printf("CRC 0x%04x wrong, expected 0x%04x\n", result, expected);
    }
}
typedef无符号字符uint8\t;
typedef无符号短crc;
crc crcTable[256];
#定义多项式0x8408
void Init()
{
crc余数;
对于(整数红利=0;红利<256;++红利)
{
剩余=股息;
用于(uint8\u t位=8;位>0;--位)
{
如果(余数和1)
余数=(余数>>1)^多项式;
其他的
余数=(余数>>1);
}
crcTable[股息]=剩余部分;
}
}
crc计算(const uint8_t*消息,整数字节,crc wOldCRC)
{
uint8_t数据;
crc余数=wOldCRC;
用于(int字节=0;字节>8);
}
返回剩余部分;
}
int main()
{
crc应为0x6f91;
uint8_t模式[]=“123456789”;
Init();
crc结果=计算(模式9,0xFFFF);
如果(结果!=预期)
{
//这个输出与问题无关,尽管C++标签
printf(“CRC 0x%04x错误,预期0x%04x\n”,结果,预期);
}
}
对于一般情况,如果输入数据被反射,那么您将反射此答案中所示的多项式,在底部输入字节,检查低位是否对多项式进行异或运算,然后上移。如果输入数据未被反射,则按照问题中的代码进行操作,保持多项式不变,在底部输入字节顶部,检查高位,然后向下移动

几乎在所有情况下,输出的反射都与输入的反射相同。对于所有这些情况,都不需要位反转功能。如果输入和输出都未反射,或者输入和输出都反射,则移位寄存器的结果保持不变。只有一种情况下,反射不同从反射输入(CRC-12/3GPP)。在这种情况下,您需要对输出进行位反转,因为输入没有反射,但输出是


初始CRC只是移位寄存器的初始内容。在启动CRC时设置一次。最终的异或应用于最后的移位寄存器内容。如果您有一个每次计算一个CRC的函数,则在输入该函数时也需要应用最终的异或,并应用t将final exclusive or设置为用户看到的初始值,这样实际的初始值就是移位寄存器中的值。

感谢这一帮助。您更改了CRC位顺序,删除了初始余数移位,在计算过程中更改了移位,并更改了位测试。当然,您删除了t中的反射函数他
计算
函数。但是哪个参数(s)受更改控制,我如何理解如何控制每个参数?您可以查看my,了解CRC参数的一般应用方式。您的CRCany代码要求在处理计算前后CRC必须是反向的。是否可以将其作为CRC表计算的参数如果
rev
成员是
1
。我的问题中没有包含此参数,但代码中有一点移位看起来有点笨拙,将替换(更多)经典CRC计算中的位移位。这不能在表计算中折叠吗?你需要阅读我上面的答案。72个CRC中只有一个需要这样的反转。在这种情况下,反转是不可避免的。与输入数据无关的是“CRC参数”。参数是多项式,即初始值值和位宽度。@EJP那么您会说,我引用的页面上的信息是错误的??但是您同意更改参数会影响CRC结果,是吗?