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

标签 c# c

我正在尝试将一些简单的 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);

我相信我在使用每种语言的相同数据调用函数,对吗?如果有人能对此有所了解,我将不胜感激。

最佳答案

@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 的 typedef 总是一个好主意.它们与 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);

关于c# - CRC 函数从 C 到 C# 的转换产生错误值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25524061/

相关文章:

c# - 用于在 SQL Server 中查询 JSON 字符串的 Entity Framework

c - VxWorks结构体操作如何保证原子性?

c - 从文件中的行读取最大单词时重复标记?

c++ - 为什么在eclipse CDT 编辑器中断点用反斜杠标记?

c# - 在 Mono 中检测符号链接(symbolic link)和管道

c# - 在 ASP.NET Core 中初始化依赖注入(inject)时传递参数

c# - MVC 3 不在区域下寻找 View

c++ - *&C程序中的指针

c - 我对链表有一些问题

c# - 使用固定长度字段的可变长度数组解析消息