4

シリアル通信でのメッセージ解析を考えていたのですが、形の違うパケットがたくさんあります。しかし、それらはすべてバイト配列で送信されます。

そこで、unionを使用して各メッセージを解析することを考えました。しかし、それはうまく機能していません。次のコードは私がエラーになっているサンプルコードです

[StructLayout(LayoutKind.Explicit, Size=12)]
public struct UnionPacket
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=12)]
    public byte[] data;

    [FieldOffset(0)]
    public float Time;
    [FieldOffset(4)]
    public Int16 CoordX;
    [FieldOffset(6)]
    public Int16 CoordY;
    [FieldOffset(8)]
    public byte Red;
    [FieldOffset(9)]
    public byte Green;
    [FieldOffset(10)]
    public byte Blue;
    [FieldOffset(11)]
    public byte Alpha;
}

これが可能であれば、それは非常に幸せですが、そうではありません。このコードはTypeLoadExceptionを発生させます。「...オフセット0にオブジェクトフィールドが含まれているため、オブジェクトフィールドが正しく配置されていないか、非オブジェクトフィールドとオーバーラップしています。」

だから私はこのようないくつかのコードを変更しました

[StructLayout(LayoutKind.Explicit, Size= 12)]
public struct UnionPacket
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
    [FieldOffset(0)]
    public byte[] data;

    //[FieldOffset(0)]
    //public float Time;
    [FieldOffset(4)]
    public Int16 CoordX;
    [FieldOffset(6)]
    public Int16 CoordY;
    [FieldOffset(8)]
    public byte Red;
    [FieldOffset(9)]
    public byte Green;
    [FieldOffset(10)]
    public byte Blue;
    [FieldOffset(11)]
    public byte Alpha;
}

テストのために、オフセットが0の時間フィールドを無効にしましたが、これは発生しませんでした。ただし、他のフィールドを変更しても、バイト配列は変更されません。バイト配列の実際のメモリ位置は他のヒープに割り当てられていると思いますので、それはできません。

C#でこの問題を解決する方法はありますか?これを解決できるのはC++またはCだけですか?これを継承で使用する場合、それは可能ですか?

PS私の貧弱な英語について申し訳ありません

4

1 に答える 1

8

私はあなたが何をしようとしているのか100%確信していませんが:

固定/安全でないキーワードで使用する場合は、構造内に配列を格納する最初のアプローチが可能です。これがあなたに可能かどうかはわかりません。したがって、このようなコードを使用すると機能するはずです。

[StructLayout(LayoutKind.Explicit, Size = 12)]
public unsafe struct UnionPacket
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
    [FieldOffset(0)]
    public fixed byte data[12];

    [FieldOffset(0)]
    public float Time;
    [FieldOffset(4)]
    public Int16 CoordX;
    [FieldOffset(6)]
    public Int16 CoordY;
    [FieldOffset(8)]
    public byte Red;
    [FieldOffset(9)]
    public byte Green;
    [FieldOffset(10)]
    public byte Blue;
    [FieldOffset(11)]
    public byte Alpha;
}

もちろん、VSで安全でないコードブロックを有効にして、構造をラップアラウンドする必要があります。

unsafe
{
    var u = new UnionPacket();
    for (byte i = 0; i < 12; i++)
    {
         u.data[i] = i;
    }
    Console.WriteLine(u.Time);
    Console.WriteLine(u.CoordX);
    Console.WriteLine(u.CoordY);        
    Console.WriteLine(u.Red);
    Console.WriteLine(u.Green);
    Console.WriteLine(u.Blue);
    Console.WriteLine(u.Alpha);
}

他のアプローチは次のようになります-struct内のこの配列を忘れて、Marshal.Copy:を使用して解析を処理します。

[StructLayout(LayoutKind.Explicit, Size = 12)]
public struct UnionPacket2
{
    [FieldOffset(0)]
    public float Time;
    [FieldOffset(4)]
    public Int16 CoordX;
    [FieldOffset(6)]
    public Int16 CoordY;
    [FieldOffset(8)]
    public byte Red;
    [FieldOffset(9)]
    public byte Green;
    [FieldOffset(10)]
    public byte Blue;
    [FieldOffset(11)]
    public byte Alpha;
}

static void Main(string[] args)
{
    var len = Marshal.SizeOf(typeof(UnionPacket2));
    var buffer = new byte[len];
    for (byte i = 0; i < len; i++)
    {
        buffer[i] = i;
    }

    var ptr = Marshal.AllocHGlobal(len);
    Marshal.Copy(buffer, 0, ptr, len);
    var u = (UnionPacket2)Marshal.PtrToStructure(ptr, typeof(UnionPacket2));
    Marshal.FreeHGlobal(ptr);
    Console.WriteLine(u.Time);
    Console.WriteLine(u.CoordX);
    Console.WriteLine(u.CoordY);
    Console.WriteLine(u.Red);
    Console.WriteLine(u.Green);
    Console.WriteLine(u.Blue);
    Console.WriteLine(u.Alpha);
}
于 2012-10-21T20:39:38.780 に答える