2014-08-27 47 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);