Как назначить байт [] в качестве указателя в C # - PullRequest
2 голосов
/ 29 марта 2009

У меня есть функция, которая генерирует контрольный байт CRC на основе содержимого любого пакета. Проблема заключается в переводе функции из C ++ в C #

C ++ код:

unsigned char GenerateCheckByte( char* packet, int length, unsigned long seed )
{
if( !packet ) return 0;
unsigned long checksum = 0xFFFFFFFF;
length &= 0x7FFF;
char* ptr = packet;
unsigned long moddedseed = seed << 8;
for( int i = 0; i < length; i++ )
    checksum = ( checksum >> 8 ) ^ table[moddedseed + ( ( *(ptr++) ^ checksum ) & 0xFF )];
unsigned char result = ( (checksum>>24)&0xFF ) + ( (checksum>>8)&0xFF ) + ( (checksum>>16)&0xFF ) + ( checksum&0xFF );
return result;
}

символ * (пакет) также может быть определен как LPBYTE, идея состоит в том, что значение, присвоенное * пакету, присваивается * ptr, и, как вы видите, * ptr увеличивается. Значение байтового массива передается и путем увеличения Значение указателя идет до следующего байта.

Я пытался сделать это в C # и много раз терпел неудачу. После некоторой тяжелой работы я разобрался с кодом, но не могу его выполнить:?

C # код

    public static unsafe byte GenerateCheckByte(byte *packet, int length, UInt32 seed )
    {
        if (*packet == 0)
        return 0;
        UInt32 checksum = 0xFFFFFFFF;
        length &= 0x7FFF;
        byte *ptr = packet;
        UInt32 moddedseed = seed << 8;
        for (int i = 0; i < length; i++)
            checksum = ( checksum >> 8 ) ^ Table.table[moddedseed + ( ( *(ptr++) ^ checksum ) & 0xFF )];
        byte result = (byte)(( (checksum>>24)&0xFF ) + ( (checksum>>8)&0xFF ) + ( (checksum>>16)&0xFF ) + ( checksum&0xFF ));
        return result;
    }

Это не выглядит так плохо, но я не могу назвать это

  unsafe
  {
      packetBuffer[5] = Functions.GenerateCheckByte(&packetBuffer[0], 18, packet.seedCRC);
  }

ошибка: «Вы можете взять только адрес нефиксированного выражения внутри инициализатора фиксированного оператора»

Обратите внимание

пакетный буфер в приложениях C ++ и C # равен byte [] packetBuffer = новый байт [18];

Ответы [ 3 ]

5 голосов
/ 29 марта 2009

Вы можете заставить метод принимать байтовый массив:

public static unsafe byte GenerateCheckByte(byte[] packetArray, int length, UInt32 seed)
{
    fixed(byte *packet = packetArray)
    {
        ... etc
    }
}

Лучше скрывать небезопасные компоненты как можно дальше за управляемыми интерфейсами.

Тогда позвонить будет легко:

packetBuffer[5] = Functions.GenerateCheckByte(packetBuffer, 18, ...

На самом деле было бы лучше написать GenerateCheckByte для работы с массивом, а не углубляться в unsafe методы:

public static unsafe byte GenerateCheckByte(byte[] packet, int length, UInt32 seed )
{
    if (packet == null)
        throw new ArgumentNullException("packet"); // the right way in C#

    UInt32 checksum = 0xFFFFFFFF;
    length &= 0x7FFF;

    UInt32 moddedseed = seed << 8;
    for (int i = 0; i < length; i++)
        checksum = ( checksum >> 8 ) ^ Table.table[moddedseed + ( ( packet[i] ^ checksum ) & 0xFF )];
    byte result = (byte)(( (checksum>>24)&0xFF ) + ( (checksum>>8)&0xFF ) + ( (checksum>>16)&0xFF ) + ( checksum&0xFF ));
    return result;
}

Напишите самую простую и безопасную реализацию, какую только можно, и связывайтесь с указателями, только если вы обнаружите узкое место в профилировании.

Вы просто переводите множество существующих C / C ++ в C #? В этом нет особого смысла, если только вы не получите от него новую безопасность / ремонтопригодность. :)

2 голосов
/ 29 марта 2009

Вам вообще не нужно использовать небезопасный код. Если вы отправите байтовый массив в функцию, он сможет получить к нему доступ без использования указателей.

Я не тестировал код, но он должен выглядеть примерно так:

byte GenerateCheckByte(byte[] packet, ulong seed) {
    if (packet == null) return 0;
    int length = packet.Length & 0x7FFF;
    ulong checksum = 0xFFFFFFFF;
    ulong moddedseed = seed << 8;
    for (int i = 0; i < length; i++) {
            checksum = (checksum >> 8) ^ table[moddedseed + ((packet[i] ^ checksum) & 0xFF)];
    }
    return (byte)(
        ((checksum >> 24) & 0xFF) +
        ((checksum >> 16) & 0xFF) +
        ((checksum >> 8) & 0xFF) +
        (checksum & 0xFF)
    );
}
1 голос
/ 29 марта 2009

Вам нужно «закрепить» байтовый массив в памяти, чтобы использовать его в качестве байта *.

byte checksum; 
fixed(byte* pPacketBuffer = packetBuffer)
{
    checksum = Functions.GenerateCheckByte(pPacketBuffer, 18, packet.seedCRC) 
}
packetBuffer[5] = checksum 

Рекомендации:

...