CRC函数从C到C#的转换产生错误的值

本文关键字:转换 错误 函数 CRC | 更新日期: 2023-09-27 18:19:30

我试图将几个简单的CRC计算函数从C转换为C#,但我似乎得到了不正确的结果。

C的功能是:

#define CRC32_POLYNOMIAL 0xEDB88320 
unsigned long CRC32Value(int i) 
{ 
  int j; 
  unsigned long ulCRC; 
  ulCRC = i; 
  for (j=8;j>0;j--) 
  { 
       if (ulCRC & 1) 
          ulCRC = (ulCRC >> 1)^CRC32_POLYNOMIAL; 
       else 
          ulCRC >>= 1; 
  } 
  return ulCRC; 
} 
unsigned long CalculateBlockCRC32(  
       unsigned long ulCount, 
       unsigned char *ucBuffer) 
{ 
  unsigned long ulTemp1; 
  unsigned long ulTemp2; unsigned long ulCRC = 0; 
  while (ulCount-- != 0) 
  { 
    ulTemp1 = (ulCRC >> 8) & 0x00FFFFFFL; 
    ulTemp2 = CRC32Value(((int)ulCRC^*ucBuffer++)&0xff); 
    ulCRC = ulTemp1^ulTemp2; 
  } 
  return(ulCRC); 
}

这些定义很好,它们取自用户手册。这些函数的C#版本是:

    private ulong CRC32POLYNOMIAL = 0xEDB88320L;
    private ulong CRC32Value(int i)
    {
        int j;
        ulong ulCRC = (ulong)i;
        for (j = 8; j > 0; j--)
        {
            if (ulCRC % 2 == 1)
            {
                ulCRC = (ulCRC >> 1) ^ CRC32POLYNOMIAL;
            }
            else
            {
                ulCRC >>= 1;
            }
        }
        return ulCRC;
    }
    private ulong CalculateBlockCRC32(ulong ulCount, byte[] ucBuffer)
    {
        ulong ulTemp1;
        ulong ulTemp2;
        ulong ulCRC=0;
        int bufind=0;
        while (ulCount-- != 0)
        {
            ulTemp1 = (ulCRC >> 8) & 0x00FFFFFFL;
            ulTemp2 = CRC32Value(((int)ulCRC ^ ucBuffer[bufind]) & 0xFF);
            ulCRC = ulTemp1 ^ ulTemp2;
            bufind++;
        }
        return ulCRC;
    }

正如我提到的,C版本和C#版本之间存在差异。一个可能的来源是我对C表达式ulCRC & 1的理解,我相信这只适用于奇数。

我这样调用C#函数:

string contents = "some data";
byte[] toBeHexed = Encoding.ASCII.GetBytes(contents);
ulong calculatedCRC = this.CalculateBlockCRC32((ulong)toBeHexed.Length, toBeHexed);

C函数的调用方式如下:

char *Buff="some data"; 
unsigned long iLen = strlen(Buff); 
unsigned long CRC = CalculateBlockCRC32(iLen, (unsigned char*) Buff);

我相信我在用每种语言调用具有相同数据的函数,对吗?如果有人能阐明这一点,我将不胜感激。

CRC函数从C到C#的转换产生错误的值

正如@Adriano Repetti已经指出的,您应该使用UInt32数据类型来代替ulong类型(它是64位无符号UInt64,而在VC++中unsigned long只有32位无符号类型)

    private UInt32 CRC32POLYNOMIAL = 0xEDB88320;
    private UInt32 CRC32Value(int i)
    {
        int j;
        UInt32 ulCRC = (UInt32)i;
        for (j = 8; j > 0; j--)
        {
            if (ulCRC % 2 == 1)
            {
                ulCRC = (ulCRC >> 1) ^ CRC32POLYNOMIAL;
            }
            else
            {
                ulCRC >>= 1;
            }
        }
        return ulCRC;
    }
    private UInt32 CalculateBlockCRC32(UInt32 ulCount, byte[] ucBuffer)
    {
        UInt32 ulTemp1;
        UInt32 ulTemp2;
        UInt32 ulCRC = 0;
        int bufind = 0;
        while (ulCount-- != 0)
        {
            ulTemp1 = (ulCRC >> 8) & 0x00FFFFFF;
            ulTemp2 = CRC32Value(((int)ulCRC ^ ucBuffer[bufind]) & 0xFF);
            ulCRC = ulTemp1 ^ ulTemp2;
            bufind++;
        }
        return ulCRC;
    }
    string contents = "12";
    byte[] toBeHexed = Encoding.ASCII.GetBytes(contents);
    UInt32 calculatedCRC = CalculateBlockCRC32((UInt32)toBeHexed.Length, toBeHexed);

通常在C#中,使用C#数据类型名称(Microsoft推荐)还是ECMA类型名称并不重要。但在这种情况下以及类似的比特级操作情况下,它可以极大地澄清意图并防止错误。

在C中,使用stdint.h中的typedefs总是一个好主意。它们与C#中的ECMA类型做着相同的工作-澄清意图,并保证所用数据类型的长度和符号(C编译器可能对相同的类型使用不同的长度,因为标准没有指定确切的大小):

#include <stdint.h>
#define CRC32_POLYNOMIAL ((uint32_t)0xEDB88320)
uint32_t CRC32Value(uint32_t i) 
{ 
  uint32_t j; 
  uint32_t ulCRC; 
  ulCRC = i; 
  for (j = 8; j > 0; j--) 
  { 
       if (ulCRC & 1) 
          ulCRC = (ulCRC >> 1) ^ CRC32_POLYNOMIAL; 
       else 
          ulCRC >>= 1; 
  } 
  return ulCRC; 
} 
uint32_t CalculateBlockCRC32(  
       size_t ulCount, 
       uint8_t *ucBuffer) 
{ 
  uint32_t ulTemp1; 
  uint32_t ulTemp2; 
  uint32_t ulCRC = 0;
  while (ulCount-- != 0) 
  { 
    ulTemp1 = (ulCRC >> 8) & ((uint32_t)0x00FFFFFF); 
    ulTemp2 = CRC32Value((ulCRC^*ucBuffer++)&0xff); 
    ulCRC = ulTemp1^ulTemp2; 
  } 
  return(ulCRC); 
}
char *Buff = "12"; 
size_t iLen = strlen(Buff); 
uint32_t CRC = CalculateBlockCRC32(iLen, (uint8_t *) Buff);
printf("%u", CRC);