2

パケットの内容に基づいて 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;
}

char*(packet) は LPBYTE として定義することもできます。考え方は、*packet に割り当てられた値が *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# の両方のアプリケーションの packetbuffer は byte[] packetBuffer = new byte[18]; です。

4

3 に答える 3

6

メソッドがバイト配列を受け入れるようにすることができます。

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# に変換しているだけですか? 新しい安全性/保守性が得られない限り、それを行う意味はほとんどありません。:)

于 2009-03-28T23:15:39.217 に答える
2

安全でないコードを使用する必要はまったくありません。関数にバイト配列を送信すると、ポインターを使用せずに関数にアクセスできます。

コードはテストしていませんが、次のようになります。

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)
    );
}
于 2009-03-28T23:30:22.033 に答える
1

バイト配列をバイトとして使用するには、メモリに「固定」する必要があります*。

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

参考文献:

于 2009-03-28T23:15:59.713 に答える