我正在尝试使用 pinvoke 将结构数组编码到另一个结构中,从 C 到 C#。据我所知,没办法。
因此,相反,在 C 结构中,我声明了指向我的数组的 ptr 和 malloc。问题: 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(); }
}
再次,编译正常,但同样的错误消息。
最佳答案
要在 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对它的工作原理有一个很好的概述,但基本思想是:
- 您应该在您的结构中添加一个字段,其中包含数组元素的计数(这将使您的生活更轻松)
- 在 C# 中将字段声明为:
IntPtr data;
没有属性。 - 使用
Marshal.SizeOf(typeof(A))
获取结构在非托管内存中的大小。 - 使用
Marshal.PtrToStructure
将单个非托管结构转换为 C# - 使用
IntPtr.Add(ptr, sizeofA)
移动到数组中的下一个结构 - 循环直到用完。
关于c# - 如何将 pinvoke 用于指向 C# 的 C 结构数组指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11968960/