CRC-16 0x8005多项式,从C到C#。 SOS

时间:2017-02-01 10:08:08

标签: c# c crc

我有这个C代码块,我无法理解我的生活。我需要为我发送给该方法的某个字节数组计算CRC-16,它应该给出msb(最高有效字节)和lsb(最低有效字节)。我还获得了一个C编写的应用程序来测试一些功能,该应用程序还为我提供了发送内容和通过COM端口接收的内容的日志。

奇怪的是我输入了我在日志this online calculator中找到的十六进制字符串,但它给了我不同的结果。

我尝试将方法翻译成C#,但我不了解某些方面:

  1. pucPTR在那里做什么(它没有在其他任何地方使用过)?
  2. 2行代码的含义是什么,第一行代表什么?
  3. 为什么在第二个短片" i"是< = 7,不应该< = 8?
  4. if语句中的最后一行表示usCRC实际上是ushort 8005?
  5. 以下是代码块:

    unsigned short CalculateCRC(unsigned char* a_szBufuer, short a_sBufferLen)
    {
        unsigned short usCRC = 0;
        for (short j = 0; j < a_sBufferLen; j++)
        {
            unsigned char* pucPtr = (unsigned char*)&usCRC;
            *(pucPtr + 1) = *(pucPtr + 1) ^ *a_szBufuer++;
            for (short i = 0; i <= 7; i++)
            {
                if (usCRC & ((short)0x8000))
                {
                    usCRC = usCRC << 1;
                    usCRC = usCRC ^ ((ushort)0x8005);
                }
                else
                    usCRC = usCRC << 1;
            }
        }
        return (usCRC);
    }
    

    这是我转换为字节数组并发送到方法的十六进制字符串: 02 00 04 a0 00 01 01 03

    这是应该从CRC演算中得出的结果: 06 35

    我收到的文件说这是整个数据的CRC16 IBM(msb,lsb)。

    有人可以帮忙吗?我已经被困了一段时间了。

    那里有能够将C方法转换为C#的代码大师吗?显然我不具备这样的资源。

2 个答案:

答案 0 :(得分:5)

首先,请注意,在C中,^运算符表示按位异或。

  
      
  1. pucPTR在那里做什么(它没有在其他任何地方使用过)?
  2.   
  3. 2行代码的含义是什么,第一行代表什么?
  4.   

通过它的外观导致错误。它仅用于获取FCS的两个字节中的一个,但代码是以依赖于endianess的方式编写的。

在处理校验和算法时,Endianess非常重要,因为它们最初是为硬件移位寄存器设计的,它们首先需要MSB,即大端。此外,CRC通常意味着数据通信,数据通信意味着发送方,协议和接收方之间可能有不同的字节顺序。

我猜这个代码只是为小端机器编写的,目的是用ms字节进行异或。代码指向第一个字节,然后使用+1指针算法到达第二个字节。更正后的代码应该是:

uint8_t puc = (unsigned int)usCRC >> 8;
puc ^= *a_szBufuer;
usCRC = (usCRC & 0xFF) | ((unsigned int)puc << 8);
a_szBufuer++;

对unsigned int的强制转换可以通过隐式整数提升来防止意外事件。

  
      
  1. 为什么在第二个短片&#34; i&#34;是&lt; = 7,不应该&lt; = 8?
  2.   

我认为这是正确的,但更可读的是它可以写​​成i < 8

  
      
  1. if语句中的最后一行表示usCRC实际上是ushort 8005?
  2.   

不,这意味着用多项式0x8005对您的FCS进行异或。请参阅this

  

我收到的文件说这是CRC16 IBM

是的,它有时被称为。虽然我记得,&#34; CRC16 IBM&#34;还涉及最终结果的一些反转(?)。我仔细检查一下。

总的来说,请小心这段代码。谁写了它并没有很多关于endianess,整数签名和隐式类型促销的线索。这是业余级代码。您应该能够在网上找到相同CRC算法的更安全,便携的专业版本。

关于这个主题的非常好的阅读是A Painless Guide To CRC

答案 1 :(得分:2)

  
      
  1. pucPTR在那里做什么(它没有在其他任何地方使用过)?
  2.   

pucPtr用于将 uglily unsigned short转换为2 unsigned char的数组。根据平台的结束,pucPtr将指向unsigned short的第一个字节,而pucPtr+1将指向unsigned short的第二个字节(反之亦然)。您必须知道此算法是针对小端还是大端设计的。

代码等价(如果代码是为big endian开发的,则是可移植的):

unsigned char rawCrc[2];
rawCrc[0] = (unsigned char)(usCRC & 0x00FF);
rawCrc[1] = (unsigned char)((usCRC >> 8) & 0x00FF);

rawCrc[1] = rawCrc[1] ^ *a_szBufuer++;

usCRC = (unsigned short)rawCrc[0] 
       | (unsigned short)((unsigned int)rawCrc[1] << 8);

对于小端,您必须反转raw[0]raw[1]

  
      
  1. 2行代码的含义是什么,第一行代表什么?
  2.   

第一行执行1中描述的 丑陋 转换。

第二行检索a_szBufuer指向的值并递增它。并且&#34; xor&#34;使用crc的第二个(或第一个,根据endianess)字节(注意*(pucPtr +1)等同于pucPtr[1])并将结果存储在crc的第二个(或第一个,根据endianess)字节内。

*(pucPtr + 1) = *(pucPtr + 1) ^ *a_szBufuer++;

相当于

pucPtr[1] = pucPtr[1] ^ *a_szBufuer++;
  
      
  1. 为什么在第二个短片&#34; i&#34;是&lt; = 7,不应该&lt; = 8?
  2.   

您必须进行8次迭代,从0到7.您可以将条件更改为i = 0; i<8i=1; i<=8

  
      
  1. if语句中的最后一行表示usCRC实际上是ushort 8005?
  2.   

不,它没有。这意味着usCRC现在等于usCRC XOR 0x8005^XOR bitwise operation (也称为或排他)。例如:

 0b1100110
^0b1001011
----------
 0b0101101