3

複雑なデータ構造を受け取る UDP クライアントを作成しています。私は C++ の構造を持っていますが、私のプログラムは C# です。

Bitfiels と共用体にはさまざまな構造があります。

構造体を手動で変換する必要がない方法はありますか?

また、C# でビットフィールドとユニオンを実装する簡単な方法はありますか?

現在、ビットフィールドのプロパティを使用していますが、これは難しい作業であり、間違いが発生する可能性が高くなります。

私が今行っている簡単な例を提供しました。それぞれ 100 行のコードを持つ約 50 の構造体があります。

例 C++:

typedef struct Message_s
{
    unsigned char var : 2;
    unsigned char var2 : 6;

    union
    {
         struct
         {
            unsigned char sVar;
            unsigned char sVar2;
         }
         char arr[32];
     }    
}Message_t;

例 C#:

 [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct Message_s
{
    private byte Field1
    public byte var
    {
       get
       {
           return (byte)(Field1 & 0x03);
       }
       set
       {
           Field1 = (byte)((Field1 & ~0x03) | value);
       }
    public byte var2
    {
       get
       {
           return (byte)(Field1 & 0xFC);
       }
       set
       {
           Field1 = (byte)((Field1 & 0x03) | value<<2);
       }
     }
//unions may be possible with properties...
}
4

2 に答える 2

4

簡単な答えはノーです。C++構造体をC#形式にする簡単な方法はないようです。ただし、C#構造体で結合を行う方法があります。これが良い考えであるかどうか、またはクラスで最初から始める方が良いかどうかは、あなた次第です。

LayoutKind.Explicit使用するC#構造体とFieldOffset属性でユニオンを取得するには、次のようにします。

[StructLayout(LayoutKind.Explicit)]
struct StructTest
{
    // A byte at the beginning of the struct.
    [FieldOffset(0)]
    public byte byte1;

    // Another byte immediately after it.
    [FieldOffset(1)]
    public byte byte2;

    // Now an integer which covers both.
    [FieldOffset(0)]
    public Int16 int1;
}

これは、期待どおりに使用できます。

        var foo = new StructTest();
        foo.byte1 = 3;
        foo.byte2 = 6;
        Console.WriteLine("{0}", foo.int1);

        var bar = new StructTest();
        bar.int1 = 5050;
        Console.WriteLine("{0}, {1}", bar.byte1, bar.byte2);

を生成1539186, 19ます。

これにより、ユニオン構造が得られますが、それでもBitFieldsの主な問題には答えられません。これについてはコンセンサスが得られていないようです(もちろん、すでに行ったことを除いて、たとえば[ 1 ]を参照してください)。MarshalAsこの属性を使用して、カスタムBitFieldクラスを基になる構造体にマップするための巧妙な方法を実行できる場合がありますが、そのレベルの作業では、これまでどおりカスタムクラスを作成し続ける方が簡単な場合があります。

于 2012-06-21T15:24:36.773 に答える
2

別の方法として、コードでアンマネージ C++ 型を使用する方法がありますが、それでも多少の型指定が必要です。VS C++ プロジェクトで、アンマネージ構造体を作成します。

struct Date_s
{
    union
    {
        struct
        {
            unsigned nWeekDay  : 3;    // 0..7   (3 bits)
            unsigned nMonthDay : 6;    // 0..31  (6 bits)
            unsigned           : 0;    // Force alignment to next boundary.
            unsigned nMonth    : 5;    // 0..12  (5 bits)
            unsigned nYear     : 8;    // 0..100 (8 bits)
        };
        unsigned bob;
    };
};

次に、この構造をラップするマネージド型を作成します。

public ref struct Date_ms
{
    AutoPtr<Date_s> data;
    Date_ms()
    {
        data = new Date_s();
    }

    property unsigned nWeekDay
    {
        unsigned get() { return data->nWeekDay; }
        void set(unsigned value) { data->nWeekDay = value; }
    }
    property unsigned nMonthDay
    {
        unsigned get() { return data->nMonthDay; }
        void set(unsigned value) { data->nMonthDay = value; }
    }
    property unsigned nMonth
    {
        unsigned get() { return data->nMonth; }
        void set(unsigned value) { data->nMonth = value; }
    }
    property unsigned nYear
    {
        unsigned get() { return data->nYear; }
        void set(unsigned value) { data->nYear = value; }
    }
    property unsigned bob
    {
        unsigned get() { return data->bob; }
        void set(unsigned value) { data->bob = value; }
    }
};

そこにいくつかのコピーと貼り付けがあります。ここで使用する外部アイテムもあります。それは KerrのAutoPtrです。T* operator=(T* rhs) { return (m_ptr = rhs); }また、イニシャライザを機能させるために、AutoPtr コードに行を追加しました(Kerr の投稿へのコメントで提案されているように)。

これで、C# コードでこの新しい構造を使用できるようになり、すべてが期待どおりに機能するはずです。

var test = new Date_ms();
test.nMonth = 3;
test.nMonthDay = 28;
test.nYear = 98;
Console.WriteLine("{0}, {1}, {2}", test.nMonth, test.nMonthDay, test.nYear);
Console.WriteLine("{0}", test.bob);

とに3, 28, 98なり224ます。

大きな巨大な警告

このようにマネージ コードとアンマネージ コードを混在させることは危険です。そのため、Kerr は最初に AutoPtr を書きました (ところで、このトピックに関する彼のブログ投稿は読む価値があります)。これは私にとってはうまくいきますが、メモリリークが発生しないことを保証することはできません. 展開する前に、これが意図したとおりに機能することを確実に確認する必要があります。

于 2012-06-22T10:51:21.320 に答える