Преобразование функции CRC из C в C # дает неправильные значения

1

Я пытаюсь преобразовать несколько простых вычислений 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); 
}

Они хорошо определены, они взяты из руководства пользователя. Мои версии С# этих функций:

    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
    unsigned long в C - это uint в C # (ну, собственно, с modopt(long) uint ). ulong в C # unsigned long long в C.
  • 1
    Если вы знаете места, где есть расхождения, вы можете не просто отладить две программы, чтобы выяснить, где они ведут себя по-разному? т.е. есть много модульных тестов и использовать их, чтобы отследить ваши ошибки.
Показать ещё 3 комментария
Теги:

1 ответ

1

Как уже указывал @Adriano UInt32 вместо типа ulong следует использовать UInt32 данных 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);

Обычно в С# не имеет значения, используете ли вы имя типа данных С# (рекомендуется Microsoft) или имя типа ECMA. Но в этом и подобных случаях с манипуляцией на уровне бит он может значительно прояснить намерение и предотвратить ошибки.

В C всегда рекомендуется использовать typedefs из stdint.h. Они выполняют ту же работу, что и типы 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);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню