我想将一个带有可变长度数组的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;
}
Apparently,不可能按原样编组可变长度数组,这是正确的还是仍然有办法实现这一目标?
答案 0 :(得分:8)
简短的回答 你不能将变长数组编组为数组,因为不知道大小,互操作编组服务不能编组数组元素
但如果您知道它的大小,就会如下:
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 struct动态分配空间,并为数据数组提供扩展空间
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));
根据偏移量获取数据数组字段的内存地址。
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;
答案 1 :(得分:-1)
在上面的例子中,我肯定会使用SizeParamIndex。
[StructLayout(LayoutKind.Sequential)]
public struct fvec_t1
{
uint length;
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] float[] data;
}
祝你好运。