编组包含可变长度数组的 C 结构 [英] Marshal a C struct containing a variable length array

查看:31
本文介绍了编组包含可变长度数组的 C 结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将带有可变长度数组的 C 结构编组回 C#,但到目前为止,我找不到比指向结构的表示形式和指向浮点的指针更好的方法了.

I would like to marshal a C struct with a variable-length array back to C# but so far I can't get anything better than a pointer-to-struct representation and a pointer to float.

非托管表示:

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[] 但如果我确实将结构更改为下面的形式,我会这样做get 无法在上面的外部函数中获取其地址、获取其大小或声明指向托管类型的指针.

What I would like is to have a .NET style array, where data would be float[] but if I do change the struct to the form below I do get Cannot take the address of, get the size of, or declare a pointer to a managed type in the external function above.

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

    public float[] data;
}

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

Apparently, it is not possible to a have a variable-length array marshalled back as-is, is this correct or is it there still a way to achieve this ?

推荐答案

简答您不能将可变长度数组编组为数组,因为在不知道大小的情况下,互操作编组服务无法编组数组元素

short answer you can't marshal variable length array as an array , because Without knowing the size, the interop marshalling service cannot marshal the array elements

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

but if you know the size it will be like below:

int arr[15]

您将能够像这样编组它:

you will be able to marshal it like this:

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

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

if you don't know the length of the array and this is what you want you can convert it to intprt and deal with inptr but first you need to create 2 structs

[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;
}

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

create a function to initialize the array like below

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 结构分配空间,并为数据数组扩展空间

dynamically allocate space for fvec_t2 struct with extended space for data array

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

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

Transfer the existing field values of fvec_t2 to memory space pointed to by ptr

Marshal.StructureToPtr(instance1, ptr, true);

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

Calculate the offset of data array field which should be at the end of an fvec_t2 struct

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

根据偏移量获取数据数组字段的内存地址.

get memory address of data array field based on the offset.

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;

这篇关于编组包含可变长度数组的 C 结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆