如何在C#中的结构中放置一个数组?

时间:2022-09-06 11:27:24

C++ code:

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;

We can't do that as easy in C#.

我们不能在C#中轻松做到这一点。

Please note there is an array in the C++ structure.

请注意,C ++结构中有一个数组。

Alternatively, using this source file could do the job for us, but not if there is an array in the structure.

或者,使用此源文件可以为我们完成工作,但如果结构中有数组则不行。

4 个解决方案

#1


I think what you are looking for (if you are using a similar structure definition like JaredPar posted) is something like this:

我认为你正在寻找的东西(如果你使用像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

#2


I'm unsure of exactly what you are asking. Are you trying to get an equivalent structure definition in C# for plain old C# usage or for interop (PInvoke) purposes? If it's for PInvoke the follownig structure will work

我不确定你究竟在问什么。您是否尝试在C#中获取等效的结构定义以用于普通的旧C#用法或用于互操作(PInvoke)目的?如果它适用于PInvoke,则follownig结构将起作用

[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;
}

If you are looking for a plain old C# structure that has the same characteristics, it's unfortunately not possible to do with a struct. You cannot define an inline array of a contstant size in a C# structure nor can you force the array to be a specific size through an initializer.

如果您正在寻找具有相同特征的普通旧C#结构,那么遗憾的是不可能使用结构。您无法在C#结构中定义常量大小的内联数组,也无法通过初始化程序强制数组为特定大小。

There are two alternative options in the managed world.

托管世界中有两种备选方案。

Use a struct which has a create method that fills out the array

使用具有填充数组的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] };
    }
}

Or alternatively use a class where you can initialize the array123 member variable directly.

或者使用一个类,您可以直接初始化array123成员变量。

EDIT OP watns to know how to convert a byte[] into a tPacket value

EDIT OP知道如何将byte []转换为tPacket值

Unfortunately there is no great way to do this in C#. C++ was awesome for this kind of task because has a very weak type system in that you could choose to view a stream of bytes as a particular structure (evil pointer casting).

不幸的是,在C#中没有很好的方法可以做到这一点。 C ++对于这种任务很棒,因为它有一个非常弱的类型系统,你可以选择将字节流视为一个特定的结构(邪恶的指针转换)。

This may be possible in C# unsafe code but I do not believe it is.

这在C#不安全代码中可能是可能的,但我不相信。

Essentially what you will have to do is manually parse out the bytes and assign them to the various values in the struct. Or write a native method which does the C style casting and PInvoke into that function.

基本上,您需要做的是手动解析字节并将它们分配给结构中的各种值。或者编写一个本地方法,将C样式转换和PInvoke转换为该函数。

#3


It can be done with unsafe code too, although it restricts the context under which your program can run, and, naturally, introduces the possibility of security flaws. The advantage is that you cast directly from an array to the structure using pointers and it's also maintenance-free if you are only going to add or remove fields from the struct. However, accessing the arrays require using the fixed-statement as the GC can still move the struct around in memory when it's contained in an object.

它也可以用不安全的代码来完成,虽然它限制了程序可以运行的上下文,并且自然会引入安全漏洞的可能性。优点是您可以使用指针直接从数组转换到结构,如果您只是在结构中添加或删除字段,它也是免维护的。但是,访问数组需要使用fixed语句,因为当GC包含在对象中时,GC仍然可以在内存中移动结构。

Here's some modified code of an unsafe struct I used for interpreting UDP packets:

这是我用于解释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
}

For this kind of code it is extremely important to check that the length of the array perfectly matches the size of the struct, otherwise you'll open for some nasty buffer overflows. As the unsafe keyword has been applied to the whole struct, you don't need to mark each method or codeblock as separate unsafe statements.

对于这种代码,检查数组的长度是否与struct的大小完全匹配是非常重要的,否则你将打开一些讨厌的缓冲区溢出。由于unsafe关键字已应用于整个结构,因此您无需将每个方法或代码块标记为单独的不安全语句。

#4


You can place what looks to the outside world like an array of fixed size within a safe structure by writing functions within the structure for access. For example, here is a fixed 4 by 4 double precision array within a safe structure:

通过在结构中编写函数进行访问,您可以将外观世界看起来像安全结构中的固定大小数组。例如,这是一个安全结构中固定的4乘4双精度数组:

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 */}              
}

#1


I think what you are looking for (if you are using a similar structure definition like JaredPar posted) is something like this:

我认为你正在寻找的东西(如果你使用像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

#2


I'm unsure of exactly what you are asking. Are you trying to get an equivalent structure definition in C# for plain old C# usage or for interop (PInvoke) purposes? If it's for PInvoke the follownig structure will work

我不确定你究竟在问什么。您是否尝试在C#中获取等效的结构定义以用于普通的旧C#用法或用于互操作(PInvoke)目的?如果它适用于PInvoke,则follownig结构将起作用

[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;
}

If you are looking for a plain old C# structure that has the same characteristics, it's unfortunately not possible to do with a struct. You cannot define an inline array of a contstant size in a C# structure nor can you force the array to be a specific size through an initializer.

如果您正在寻找具有相同特征的普通旧C#结构,那么遗憾的是不可能使用结构。您无法在C#结构中定义常量大小的内联数组,也无法通过初始化程序强制数组为特定大小。

There are two alternative options in the managed world.

托管世界中有两种备选方案。

Use a struct which has a create method that fills out the array

使用具有填充数组的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] };
    }
}

Or alternatively use a class where you can initialize the array123 member variable directly.

或者使用一个类,您可以直接初始化array123成员变量。

EDIT OP watns to know how to convert a byte[] into a tPacket value

EDIT OP知道如何将byte []转换为tPacket值

Unfortunately there is no great way to do this in C#. C++ was awesome for this kind of task because has a very weak type system in that you could choose to view a stream of bytes as a particular structure (evil pointer casting).

不幸的是,在C#中没有很好的方法可以做到这一点。 C ++对于这种任务很棒,因为它有一个非常弱的类型系统,你可以选择将字节流视为一个特定的结构(邪恶的指针转换)。

This may be possible in C# unsafe code but I do not believe it is.

这在C#不安全代码中可能是可能的,但我不相信。

Essentially what you will have to do is manually parse out the bytes and assign them to the various values in the struct. Or write a native method which does the C style casting and PInvoke into that function.

基本上,您需要做的是手动解析字节并将它们分配给结构中的各种值。或者编写一个本地方法,将C样式转换和PInvoke转换为该函数。

#3


It can be done with unsafe code too, although it restricts the context under which your program can run, and, naturally, introduces the possibility of security flaws. The advantage is that you cast directly from an array to the structure using pointers and it's also maintenance-free if you are only going to add or remove fields from the struct. However, accessing the arrays require using the fixed-statement as the GC can still move the struct around in memory when it's contained in an object.

它也可以用不安全的代码来完成,虽然它限制了程序可以运行的上下文,并且自然会引入安全漏洞的可能性。优点是您可以使用指针直接从数组转换到结构,如果您只是在结构中添加或删除字段,它也是免维护的。但是,访问数组需要使用fixed语句,因为当GC包含在对象中时,GC仍然可以在内存中移动结构。

Here's some modified code of an unsafe struct I used for interpreting UDP packets:

这是我用于解释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
}

For this kind of code it is extremely important to check that the length of the array perfectly matches the size of the struct, otherwise you'll open for some nasty buffer overflows. As the unsafe keyword has been applied to the whole struct, you don't need to mark each method or codeblock as separate unsafe statements.

对于这种代码,检查数组的长度是否与struct的大小完全匹配是非常重要的,否则你将打开一些讨厌的缓冲区溢出。由于unsafe关键字已应用于整个结构,因此您无需将每个方法或代码块标记为单独的不安全语句。

#4


You can place what looks to the outside world like an array of fixed size within a safe structure by writing functions within the structure for access. For example, here is a fixed 4 by 4 double precision array within a safe structure:

通过在结构中编写函数进行访问,您可以将外观世界看起来像安全结构中的固定大小数组。例如,这是一个安全结构中固定的4乘4双精度数组:

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 */}              
}