2014-08-27 42 views
1

我试图将几个简单的CRC计算函数从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); 

我相信我打电话,在每一种语言相同的数据的功能, 那是对的吗?如果有人能够对此有所了解,我将非常感激。

+1

C中的'unsigned long'是C#中的'uint'(实际上使用'modopt(long)uint')。 C中的'ulong'是C中的'unsigned long long'。 – 2014-08-27 09:58:22

+1

如果你知道有些地方存在差异,你能不能仅仅调试两个程序来找出它们的行为不同?即有很多单元测试并用它们来追踪你的错误。 – Chris 2014-08-27 09:59:00

+0

另外我认为这可能更适合http://codereview.stackexchange.com/(尽管我可能是错的,我不常去那里)。堆栈溢出更多的是帮助解决特定的问题,而不仅仅是“我的程序没有达到我期望的水平”。 – Chris 2014-08-27 10:01:58

回答

1

因为已经通过@Adriano Repetti被已经指出应该代替ulong类型的使用UInt32数据类型(它是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);