Marshal包含可变长度数组的C结构

我想将一个带有可变长度数组的C结构编组回C#,但到目前为止,我无法获得比指向结构表示和浮点指针更好的结果。

未管理的代表:

typedef float smpl_t; typedef struct { uint_t length; /**< length of buffer */ smpl_t *data; /**< data vector of length ::fvec_t.length */ } fvec_t; 

管理代表:

 [StructLayout(LayoutKind.Sequential)] public unsafe struct fvec_t1 { public uint length; public float* data; } [DllImport("libaubio-4.dll", EntryPoint = "new_fvec", PreserveSig = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern unsafe fvec_t1* new_fvec1(uint length); 

我想要的是一个.NET样式数组,其中data将是float[]但是如果我确实将结构更改为下面的表单,我会得到无法获取地址,获取大小或声明指针上面外部函数中的托管类型

 [StructLayout(LayoutKind.Sequential)] public unsafe struct fvec_t1 { public uint length; public float[] data; } 

显然 ,不可能有一个可变长度的arrays按原样编组,这是正确的还是仍然有办法实现这一目标?

简短的回答你不能编组可变长度数组作为数组,因为不知道大小,互操作编组服务不能编组数组元素

但如果您知道尺寸,它将如下所示:

 int arr[15] 

你将能够像这样编组它:

 [MarshalAs(UnmanagedType.LPArray, SizeConst=15)] int[] arr 

如果你不知道数组的长度这是你想要的,你可以将它转换为intprt并处理inptr但首先你需要创建2个结构

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] struct fvec_t1 { public uint whatever; public int[] data; } 

另一个如下:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] struct fvec_t2{ public uint whatever; } 

创建一个函数来初始化数组,如下所示

 private static int[] ReturnIntArray() { int [] myInt = new int[30]; for (int i = 0; i < myInt.length; i++) { myInt[i] = i + 1; } return myInt; } 

实例化第一个结构

 fvec_t1 instance = new fvec_t1(); instance.whatever=10; instance.data= ReturnIntArray(); 

实例化第二个结构

 fvec_t2 instance1 = new fvec_t2(); instance1.whatever = instance.whatever 

为数据数组的扩展空间动态分配fvec_t2结构的空间

 IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(fvec_t2)) + Instance.data.Length); 

将fvec_t2的现有字段值传输到ptr指向的内存空间

 Marshal.StructureToPtr(instance1, ptr, true); 

计算应该位于fvec_t2结构末尾的数据数组字段的偏移量

 int offset = Marshal.SizeOf(typeof(fvec_t2)); 

根据偏移量获取数据arrays字段的内存地址。

 IntPtr address = new IntPtr(ptr.ToInt32() + offset); 

将数据复制到ptr

 Marshal.Copy(instance.data, 0, address, instance.data.Length); 

打电话

 bool success = dllfunction(ptr); Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; 

在上面的例子中,我肯定会使用SizeParamIndex。

 [StructLayout(LayoutKind.Sequential)] public struct fvec_t1 { uint length; [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] float[] data; } 

祝好运。