如何在C#中的结构中放置数组?
C++代码:如何在C#中的结构中放置数组?,c#,c++,pointers,code-translation,C#,C++,Pointers,Code Translation,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++结构中有一个数组。
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++结构中有一个数组。
或者,使用可以为我们完成这项工作,但如果结构中有数组,则不行。我不确定您的确切要求。你是想在C语言中获得一个等价的结构定义,用于普通的旧C语言用法还是用于互操作(PInvoke)?如果是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#结构,那么很遗憾,不可能使用struct。不能在C#结构中定义连续大小的内联数组,也不能通过初始值设定项强制数组为特定大小
在托管世界中有两种备选方案
使用具有填充数组的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成员变量的类
编辑了解如何将字节[]转换为tPacket值
不幸的是,在C#中没有很好的方法可以做到这一点。C++对于这种任务来说是非常棒的,因为它有一个非常弱的类型系统,你可以选择将字节流看作一个特定的结构(邪恶指针铸造)。p>
这在C#不安全代码中是可能的,但我不相信
基本上,您需要做的是手动解析出字节,并将它们分配给结构中的各种值。或者编写一个本机方法,在该函数中执行C风格的强制转换和PInvoke 我认为您想要的(如果您使用类似于JaredPar posted的结构定义)是这样的:
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
这也可以用不安全的代码来完成,尽管它限制了程序可以运行的上下文,并且很自然地引入了安全缺陷的可能性。 优点是使用指针直接从数组强制转换到结构,并且如果只想在结构中添加或删除字段,则也可以免维护。但是,访问数组需要使用fixed语句,因为当结构包含在对象中时,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
}
使用系统;
使用System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
公共不安全结构UnsafePacket
{
整数时间;
短id0;
固定浮动acc[3];
短id1;
固定浮垫[9];
公共非安全数据包(字节[]rawData)
{
if(rawData==null)
抛出新的ArgumentNullException(“rawData”);
if(sizeof(byte)*rawData.Length!=sizeof(UnsafePacket))
抛出新ArgumentException(“rawData”);
已修复(字节*ptr=&rawData[0])
{
this=*(UnsafePacket*)rawPtr;
}
}
公共浮点数(整数索引)
{
如果(索引<0 | |索引>=3)
抛出新ArgumentOutOfRangeException(“索引”);
固定(未安全数据包*ptr=&acc)
{
返回ptr[索引];
}
}
公共浮点数(整数索引)
{
如果(索引<0 | |索引>=9)
抛出新ArgumentOutOfRangeException(“索引”);
固定(未安全数据包*ptr=&mat)
{
返回ptr[索引];
}
}
//其他物业等
}
对于这类代码,检查数组的长度是否与结构的大小完全匹配是非常重要的,否则会导致严重的缓冲区溢出。由于unsafe关键字已应用于整个结构,您不需要将每个方法或代码块标记为单独的不安全语句。您可以通过在结构中编写函数进行访问,将外部看起来像固定大小的数组的内容放在安全结构中。例如,这里是安全结构中的固定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 */}
}
@John,两个示例都包含结构中的数组。我不太清楚你在说什么asking@JaredParC++代码与接收数据包一起使用。当数据包被接收时,变量包将数据存储在结构TBACK中,然后访问它们。真正的成员是大小、Opcode、SyrCRC、Sead Stand、加密数据和致命的一条——小鱼。哪一个是数组。我在问如何用C#实现它?把数据放在结构中,就像C++中的数据一样。请检查上面的代码。很棒的答案。帮助我解决了一个从C到C++的数组成员传递结构问题。谢谢此外,您不必将此代码放入不安全的块中。scotty2012,谢谢。我在字节顺序上有一些问题,但我会自己解决。如果没有,我会再发一个问题。谢谢你们两位!有时,您必须处理结构布局属性中的包设置。我认为c#中的默认值是8字节,但c是4字节,或者类似的东西。我记不清了。避免在实例方法中修改结构的字段,而不是属性设置器。要么公开
此[int,int]
属性,要么公开将Matrix4
作为ref
参数的静态方法。