2

C ++コード:

struct tPacket
{
    WORD word1;
    WORD word2;
    BYTE byte1;
    BYTE byte2;
    BYTE array123[8];
}

static char data[8192] = {0};
...
some code to fill up the array
...
tPacket * packet = (tPacket *)data;

C#ではこれを簡単に行うことはできません。

C++構造には配列があることに注意してください。

あるいは、このソースファイルを使用することで作業を行うことができますが、構造体に配列がある場合はできません。

4

4 に答える 4

8

あなたが何を求めているのか正確にはわかりません。単純な古い C# の使用または相互運用 (PInvoke) の目的で、C# で同等の構造定義を取得しようとしていますか? PInvoke の場合は、次の構造が機能します

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct tPacket {

    /// WORD->unsigned short
    public ushort word1;

    /// WORD->unsigned short
    public ushort word2;

    /// BYTE->unsigned char
    public byte byte1;

    /// BYTE->unsigned char
    public byte byte2;

    /// BYTE[8]
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=8, ArraySubType=System.Runtime.InteropServices.UnmanagedType.I1)]
    public byte[] array123;
}

同じ特性を持つ単純な古い C# 構造体を探している場合、残念ながら構造体を使用することはできません。C# 構造体で定数サイズのインライン配列を定義することはできません。また、初期化子を使用して配列を特定のサイズに強制することもできません。

管理された世界には 2 つの代替オプションがあります。

配列を埋める create メソッドを持つ構造体を使用します

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct tPacket {
    public ushort word1;
    public ushort word2;
    public byte byte1;
    public byte byte2;
    public byte[] array123;
    public static tPacket Create() { 
      return new tPacket() { array123 = new byte[8] };
    }
}

または、代わりに、array123 メンバー変数を直接初期化できるクラスを使用します。

編集OPは、バイト[]をtPacket値に変換する方法を知るために待機します

残念ながら、C# でこれを行う優れた方法はありません。C++ は、バイトのストリームを特定の構造 (悪意のあるポインター キャスト) として表示することを選択できるという点で非常に弱い型システムを持っているため、この種のタスクには最適でした。

これは C# の安全でないコードで可能かもしれませんが、そうではないと思います。

基本的に、バイトを手動で解析し、構造体のさまざまな値に割り当てる必要があります。または、C スタイルのキャストと PInvoke をその関数に実行するネイティブ メソッドを記述します。

于 2009-03-27T16:15:35.723 に答える
1

アクセス用の構造内に関数を記述することにより、安全な構造内に固定サイズの配列のように見えるものを配置できます。たとえば、安全な構造内の固定された4x4の倍精度配列は次のとおりです。

public struct matrix4 //  4 by 4 matrix  
{  
    //  
    //  Here we will create a square matrix that can be written to and read from similar  
    //  (but not identical to) using an array.  Reading and writing into this structure  
    //  is slower than using an array (due to nested switch blocks, where nest depth  
    //  is the dimensionality of the array, or 2 in this case).  A big advantage of this  
    //  structure is that it operates within a safe context.  
    //  
    private double a00; private double a01; private double a02; private double a03;  
    private double a10; private double a11; private double a12; private double a13;  
    private double a20; private double a21; private double a22; private double a23;  
    private double a30; private double a31; private double a32; private double a33;  
    //
    public void AssignAllZeros()                    //  Zero out the square matrix  
    { /* code */}               
    public double Determinant()                     //  Common linear algebra function  
    { /* code */}  
    public double Maximum()                         //  Returns maximum value in matrix  
    { /* code */}  
    public double Minimum()                         //  Minimum value in matrix  
    { /* code */}  
    public double Read(short row, short col)        //  Outside read access   
    { /* code */}  
    public double Read(int row, int col)            //  Outside read access overload  
    { /* code */}  
    public double Sum()                             //  Sum of 16 double precision values  
    {  
        return a00 + a01 + a02 + a03 + a10 + a11 + a12 + a13 + a20 + a21 + a22 + a23 + a30 + a31 + a32 + a33;  
    }  
    public void Write(short row, short col, double doubleValue)  //  Write access to matrix  
    { /* code */}  
    public void Write(int row, int col, double doubleValue)      //  Write access overload  
    { /* code */}              
}
于 2012-03-01T19:20:55.273 に答える
1

安全でないコードでも実行できますが、プログラムを実行できるコンテキストが制限され、当然、セキュリティ上の欠陥が発生する可能性があります。利点は、ポインターを使用して配列から構造体に直接キャストできることです。また、構造体にフィールドを追加または削除するだけの場合は、メンテナンスフリーです。ただし、配列にアクセスするには、固定ステートメントを使用する必要があります。これは、GCがオブジェクトに含まれている場合でも、構造体をメモリ内で移動できるためです。

これは、UDPパケットの解釈に使用した安全でない構造体の変更されたコードです。

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public unsafe struct UnsafePacket
{
    int time;
    short id0;
    fixed float acc[3];
    short id1;
    fixed float mat[9];

    public UnsafePacket(byte[] rawData)
    {
        if (rawData == null)
            throw new ArgumentNullException("rawData");
        if (sizeof(byte) * rawData.Length != sizeof(UnsafePacket))
            throw new ArgumentException("rawData");

        fixed (byte* ptr = &rawData[0])
        {
            this = *(UnsafePacket*)rawPtr;
        }
    }

    public float GetAcc(int index)
    {
        if (index < 0 || index >= 3)
            throw new ArgumentOutOfRangeException("index");
        fixed (UnsafePacket* ptr = &acc)
        {
            return ptr[index];
        }
    }

    public float GetMat(int index)
    {
        if (index < 0 || index >= 9)
            throw new ArgumentOutOfRangeException("index");
        fixed (UnsafePacket* ptr = &mat)
        {
            return ptr[index];
        }
    }

            // etc. for other properties
}

この種のコードでは、配列の長さが構造体のサイズと完全に一致していることを確認することが非常に重要です。一致していないと、厄介なバッファオーバーフローが発生する可能性があります。unsafeキーワードは構造体全体に適用されているため、各メソッドまたはコードブロックを個別の安全でないステートメントとしてマークする必要はありません。

于 2009-03-27T17:08:15.020 に答える
1

あなたが探しているものは次のようなものだと思います (投稿された JaredPar のような同様の構造定義を使用している場合)。

tPacket t = new tPacket();
byte[] buffer = new byte[Marshal.SizeOf(typeof(tPacket))];
socket.Receive(buffer, 0, buffer.length, 0);

GCHandle pin = GCHandle.Alloc(buffer, GCHandleType.Pinned);
t = (tPacket)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(tPacket));
pin.free();

//do stuff with your new tPacket t
于 2009-03-27T16:44:46.230 に答える