我正在尝试使用pinvoke来编组从C到C#的另一个结构内的结构数组。 AFAIK,不能做。
所以相反,在C结构中,我向我的数组和malloc声明了一个ptr。问题:1)如何在C#端声明等效? 2)如何在C#端分配和使用等效文件?
//The C code
typedef struct {
int a;
int b; } A;
typedef struct {
int c;
// A myStruct[100]; // can't do this, so:
A *myStruct; } B;
//The c# code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class A{
int a;
int b;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class B{
int c;
// can't declare array of [100] A structures...
?
}
[编辑]:不知何故,我误解了我在别处读到的关于c#侧固定数组对象的内容。 我可以修复C中的数组大小所以编译好了,但是在使用时我得到“对象引用没有设置为对象的实例”:
data.B[3].a = 4567;
所以,在其他地方读到这个错误可能是什么,我添加了这个方法:
public void initA()
{
for (int i = 0; i < 100; i++) { B[i] = new A(); }
}
再次编译好,但错误信息相同。
答案 0 :(得分:5)
要在C和C#之间编组像这样的“复杂”结构,你有几个选择。
在这种情况下,我强烈建议您尝试将固定数组嵌入到C端结构中,因为它会大大简化C#端。您可以使用MarshalAs
属性告诉C#在运行时需要在阵列中分配多少空间:
// In C:
typedef struct
{
int a;
int b;
} A;
typedef struct
{
int c;
A data[100];
} B;
// In C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct A
{
int a;
int b;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct B
{
int c;
[MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
A[] data = new data[100];
}
如果您不知道或无法指定数组的固定大小,那么您需要执行您所做的操作并将其声明为C中的指针。在这种情况下,您无法告诉C#阵列在运行时将使用多少内存,所以你几乎完全不习惯手工编写所有的编组。 This question对其运作方式有一个很好的概述,但基本思路是:
IntPtr data;
,没有属性。Marshal.SizeOf(typeof(A))
在非托管内存中获取结构的大小。 Marshal.PtrToStructure
将单个非托管结构转换为C#IntPtr.Add(ptr, sizeofA)
移动到数组中的下一个结构