C++ CCITT CRC 16 位起始值 0xffff

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21252069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:34:08  来源:igfitidea点击:

CCITT CRC 16 Bit Start Value 0xffff

c++checksumcrccrc16

提问by Ruaan Volschenk

I need to calculate a CCITT 16 bit checksum value for data passed as a parameter together with the length. If I fill my array TempStr with the test data "123456789", use the polynomial 0x8408 with the length excluding the null termination character, I get the result string 6E90(Hex). Together with the null termination char I get 907A. When I swap out the polynomial to 0x1201 then I get results 29E2(Hex) and EFE8(Hex) with and without termination character.

我需要计算作为参数与长度一起传递的数据的 CCITT 16 位校验和值。如果我用测试数据“123456789”填充我的数组 TempStr,使用长度不包括空终止字符的多项式 0x8408,我得到结果字符串 6E90(Hex)。连同空终止字符,我得到 907A。当我将多项式交换为 0x1201 时,我会得到带有和不带有终止符的结果 29E2(Hex) 和 EFE8(Hex)。

My questions are: Do I need to calculate the CRC with or without the null termination character to obtain the correct value? Do I use the polynomial 0x1201 or the reverse polynomial 0x8408 in the algorithm? Is the correct CRC of the given data 0x29B1? I need the correct value to determine if the function works correctly.. Is the algorithm to calculate this specific CRC type correct? wData=(unsigned int)0xff & *pData++?? If someone can explain to me what is wrong and how to fix my problem I would much appreciate it. Thank you

我的问题是:我是否需要计算带有或不带有空终止符的 CRC 以获得正确的值?我在算法中使用多项式 0x1201 还是逆多项式 0x8408?给定数据 0x29B1 的 CRC 是否正确?我需要正确的值来确定函数是否正常工作。计算此特定 CRC 类型的算法是否正确?wData=(unsigned int)0xff & *pData++?? 如果有人可以向我解释出了什么问题以及如何解决我的问题,我将不胜感激。谢谢

This is the code that uses and displays the calculate_CRC16 function:

这是使用和显示 calculate_CRC16 函数的代码:

CHAR_t TestStr[] = {"123456789"};
unsigned short CrcTest = calculate_CRC16(TestStr,sizeof(TestStr)-1);
QString CrcDisplay = QString("CrcTest : %1").arg(CrcTest);
ui->txtDebug->setText(CrcDisplay);

This is the calculate_CRC16 function:

这是calculate_CRC16 函数:

UINT16_t MainWindow::calculate_CRC16(CHAR_t* pData, UINT16_t wLength)
{

  UCHAR_t i;
  UINT16_t wData;
  UINT16_t wCrc = 0xffff;

  if (wLength == 0)
    return (~wCrc);

  do
  {
    for (i=0, wData=(unsigned int)0xff & *pData++; i < 8; i++, wData >>= 1)
    {
        if ((wCrc & 0x0001) ^ (wData & 0x0001))
            wCrc = (wCrc >> 1) ^ CRC_POLY;
        else  wCrc >>= 1;
    }
  } while (--wLength);

  wCrc = ~wCrc;
  wData = wCrc;
  wCrc = (wCrc << 8) | (wData >> 8 & 0xff);

  return (wCrc);
}

采纳答案by Mark Adler

The result of 0x29b1is for the "false" CCITT CRC-16(link to CRC catalog). Which is apparently the one you need. From the catalog:

结果0x29b1“假”CCITT CRC-16(链接到CRC 目录)。这显然是你需要的。从目录:

width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 name="CRC-16/CCITT-FALSE"

So there is no bit reversal (refin, refoutfalse). The CRC is initialized with 0xffffand is not post-processed.

所以没有位反转(refinrefout假)。CRC 被初始化0xffff并且没有被后处理。

To fix your code with the least changes:

要以最少的更改修复您的代码:

if (wLength == 0)
    return wCrc;

do
{
    for (i=0, wData=((unsigned int)0xff & *pData++) << 8; i < 8; i++, wData <<= 1)
    {

        if ((wCrc & 0x8000) ^ (wData & 0x8000))
            wCrc = (wCrc << 1) ^ 0x1021;
        else  wCrc <<= 1;
    }
} while (--wLength);

return wCrc & 0xffff;

or to do it more reasonably:

或者更合理地做到这一点:

while (wLength--) {
    wCrc ^= *(unsigned char *)pData++ << 8;
    for (i=0; i < 8; i++)
        wCrc = wCrc & 0x8000 ? (wCrc << 1) ^ 0x1021 : wCrc << 1;
}
return wCrc & 0xffff;

回答by Mats Petersson

If you have a look at, it will calculate the CRC for different strings (or hex sequences, for checking with or without NUL) http://www.lammertbies.nl/comm/info/crc-calculation.html

如果您查看一下,它将计算不同字符串(或十六进制序列,用于检查是否使用 NUL)的 CRC http://www.lammertbies.nl/comm/info/crc-calculation.html

According to that, you should NOT calculate including the terminating zero to get the value of 0x29B1 for your calculation.

据此,您不应该计算包括终止零来获得 0x29B1 的值进行计算。

Since you are starting with the low bit, you should be using the "non-reverse" polynomial.

由于您从低位开始,您应该使用“非反向”多项式。

I think the problem is that you are shifting the wrong way when you are shifting the "wCrc" in your calculation.

我认为问题在于您在计算中移动“wCrc”时移动的方式错误。

In other words:

换句话说:

wCrc = (wCrc >> 1) ^ CRC_POLY;

should be:

应该:

wCrc = (wCrc << 1) ^ CRC_POLY;

and likewise:

同样:

wCrc >>= 1;

should be:

应该:

wCrc <<= 1;

However, I'm not 100% certain.

但是,我不是 100% 确定。

回答by Craig McQueen

There are a number of different variants of CRC algorithms.

CRC 算法有许多不同的变体。

  • Bit-by-bit calculation versus lookup-table
  • Reflected bytes versus non-reflected bytes (MSbit or LSbit first).
  • Appending of augmented bits at the end of the message, or not.
  • 逐位计算与查找表
  • 反射字节与非反射字节(MSbit 或 LSbit 在前)。
  • 在消息末尾附加增强位,或者不附加。

That last point is a matter of confusion. Going back to CRC theory, CRC can be seen as long division in GF(2), where the result is the remainder of long division. To do a correct calculation according to base theory, nzero bits must be appended to the end of the message in order to get the right answer. There are CRC algorithms which do the calculation this way.

最后一点是一个混乱的问题。回到CRC理论,CRC可以看作GF(2)中的长除法,其结果是长除法的余数。为了根据基础理论进行正确的计算,必须在消息末尾附加n 个零位以获得正确的答案。有 CRC 算法以这种方式进行计算。

However, more commonly CRC algorithms are done a different way, so that the message doesn't need zero bits appended to the end of the message. This calculation is often called the "direct algorithm". It is more convenient to use, and functionally equivalent, exceptthat any "initial value" of the algorithm needs to be modified to account for this variant algorithm.

但是,更常见的 CRC 算法是以不同的方式完成的,因此消息不需要在消息末尾附加零位。这种计算通常被称为“直接算法”。除了需要修改算法的任何“初始值”以考虑这种变体算法之外,它使用起来更方便,并且在功能上等效。

In the case of CRC-16/CCITT, this results in confusion as to the correct initial value: should it be 0xFFFFor 0x1D0F? Arguably, 0xFFFFis the correct initial value for the algorithm that appends augmented bits to the message. If using the "direct algorithm", the initial value must be set to 0x1D0Fto get the same result.

在 CRC-16/CCITT 的情况下,这会导致对正确初始值的混淆:应该是0xFFFF还是0x1D0F?可以说,0xFFFF是将增强位附加到消息的算法的正确初始值。如果使用“直接算法”,则必须设置初始值0x1D0F以获得相同的结果。

So you need to be aware of this difference, and use whichever one is needed to inter-work with the program/system you're interfacing with.

因此,您需要了解这种差异,并使用需要的任何一种来与您所连接的程序/系统进行交互。

Further reading:

进一步阅读: