CRC-16 0x8005 多项式,从 C 到 C#。紧急求救
CRC-16 0x8005 polynominal, from C to C#. SOS
我有这块 C 代码,我一生都无法理解。我需要为我发送给该方法的某个字节数组计算 CRC-16,它应该给我 msb(最高有效字节)和 lsb(最低有效字节)。我还获得了一个 C 编写的应用程序来测试某些功能,该应用程序还为我提供了通过 COM 端口发送和接收的内容的日志。
奇怪的是,我将在日志中找到的十六进制字符串输入 this online calculator,但它给了我不同的结果。
我试着将方法翻译成 C#,但我不明白某些方面:
- pucPTR 在那里做什么(它没有在其他任何地方使用)?
- 第一行下面的两行代码是什么意思?
- 为什么第二个短 "i" 是 <=7,不应该是 <=8?
- if 语句中的最后一行是否意味着 usCRC 实际上是 ushort 8005?
这是代码块:
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# 的代码大师?显然我没有能力提供这种资源。
- What is pucPTR doing there (it's not beeing used anywhere else)?
pucPtr
用于将丑化一个unsigned short
到2[=16=的数组].根据平台的字节序,pucPtr
将指向 unsigned short
的第一个字节,而 pucPtr+1
将指向 unsigned short
的第二个字节(反之亦然)。你必须知道这个算法是为小端还是大端设计的。
等效代码(并且可移植,如果代码是为大端开发的):
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]
- What do the 2 lines of code mean, under the first for?
第一行做 1.ugly 中描述的转换。
第二行检索 a_szBufuer
指向的值并增加它。并使用 crc 的第二个(或第一个,根据字节序)字节执行 "xor"(注意 *(pucPtr +1)
相当于 pucPtr[1]
)并将结果存储在第二个(或第一个,根据字节序)字节中crc.
*(pucPtr + 1) = *(pucPtr + 1) ^ *a_szBufuer++;
等同于
pucPtr[1] = pucPtr[1] ^ *a_szBufuer++;
- Why in the second for the short "i" is <=7, shouldn't it be <=8?
您必须进行 8 次迭代,从 0 到 7。您可以将条件更改为 i = 0; i<8
或 i=1; i<=8
- Last line in if statement means that usCRC is in fact ushort 8005?
不,不是。这意味着 usCRC
现在等于 usCRC
XOR 0x8005
。 ^
是 XOR bitwise operation (也称为 or-exclusive)。示例:
0b1100110
^0b1001011
----------
0b0101101
首先请注意,在 C 中,^
运算符表示按位异或。
- What is pucPTR doing there (it's not beeing used anywhere else)?
- What do the 2 lines of code mean, under the first for?
从表面上看会导致错误。只是用来抓取FCS的两个字节之一,但是代码写的是endianess-dependent的方式。
字节序在处理校验和算法时非常重要,因为它们最初是为硬件移位寄存器设计的,需要 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 的转换是为了可移植地防止隐式整数提升的事故。
- Why in the second for the short "i" is <=7, shouldn't it be <=8?
我认为它是正确的,但更易读的是它可以写成 i < 8
。
- Last line in if statement means that usCRC is in fact ushort 8005?
不,这意味着将您的 FCS 与多项式 0x8005 进行异或。参见 this。
The document I have been given says that this is a CRC16 IBM
是的,有时也这么叫。尽管据我记得,"CRC16 IBM" 还涉及最终结果的一些位反转(?)。我会仔细检查一下。
总体而言,请谨慎使用此代码。编写它的人对字节序、整数符号和隐式类型提升没有太多线索。它是 amateur-level 代码。您应该能够在网上找到相同 CRC 算法的更安全、便携的专业版本。
非常好的阅读主题是 A Painless Guide To CRC。
我有这块 C 代码,我一生都无法理解。我需要为我发送给该方法的某个字节数组计算 CRC-16,它应该给我 msb(最高有效字节)和 lsb(最低有效字节)。我还获得了一个 C 编写的应用程序来测试某些功能,该应用程序还为我提供了通过 COM 端口发送和接收的内容的日志。
奇怪的是,我将在日志中找到的十六进制字符串输入 this online calculator,但它给了我不同的结果。
我试着将方法翻译成 C#,但我不明白某些方面:
- pucPTR 在那里做什么(它没有在其他任何地方使用)?
- 第一行下面的两行代码是什么意思?
- 为什么第二个短 "i" 是 <=7,不应该是 <=8?
- if 语句中的最后一行是否意味着 usCRC 实际上是 ushort 8005?
这是代码块:
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# 的代码大师?显然我没有能力提供这种资源。
- What is pucPTR doing there (it's not beeing used anywhere else)?
pucPtr
用于将丑化一个unsigned short
到2[=16=的数组].根据平台的字节序,pucPtr
将指向 unsigned short
的第一个字节,而 pucPtr+1
将指向 unsigned short
的第二个字节(反之亦然)。你必须知道这个算法是为小端还是大端设计的。
等效代码(并且可移植,如果代码是为大端开发的):
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]
- What do the 2 lines of code mean, under the first for?
第一行做 1.ugly 中描述的转换。
第二行检索 a_szBufuer
指向的值并增加它。并使用 crc 的第二个(或第一个,根据字节序)字节执行 "xor"(注意 *(pucPtr +1)
相当于 pucPtr[1]
)并将结果存储在第二个(或第一个,根据字节序)字节中crc.
*(pucPtr + 1) = *(pucPtr + 1) ^ *a_szBufuer++;
等同于
pucPtr[1] = pucPtr[1] ^ *a_szBufuer++;
- Why in the second for the short "i" is <=7, shouldn't it be <=8?
您必须进行 8 次迭代,从 0 到 7。您可以将条件更改为 i = 0; i<8
或 i=1; i<=8
- Last line in if statement means that usCRC is in fact ushort 8005?
不,不是。这意味着 usCRC
现在等于 usCRC
XOR 0x8005
。 ^
是 XOR bitwise operation (也称为 or-exclusive)。示例:
0b1100110
^0b1001011
----------
0b0101101
首先请注意,在 C 中,^
运算符表示按位异或。
- What is pucPTR doing there (it's not beeing used anywhere else)?
- What do the 2 lines of code mean, under the first for?
从表面上看会导致错误。只是用来抓取FCS的两个字节之一,但是代码写的是endianess-dependent的方式。
字节序在处理校验和算法时非常重要,因为它们最初是为硬件移位寄存器设计的,需要 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 的转换是为了可移植地防止隐式整数提升的事故。
- Why in the second for the short "i" is <=7, shouldn't it be <=8?
我认为它是正确的,但更易读的是它可以写成 i < 8
。
- Last line in if statement means that usCRC is in fact ushort 8005?
不,这意味着将您的 FCS 与多项式 0x8005 进行异或。参见 this。
The document I have been given says that this is a CRC16 IBM
是的,有时也这么叫。尽管据我记得,"CRC16 IBM" 还涉及最终结果的一些位反转(?)。我会仔细检查一下。
总体而言,请谨慎使用此代码。编写它的人对字节序、整数符号和隐式类型提升没有太多线索。它是 amateur-level 代码。您应该能够在网上找到相同 CRC 算法的更安全、便携的专业版本。
非常好的阅读主题是 A Painless Guide To CRC。