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

问题描述 投票:8回答:2

我想将具有可变长度数组的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,不可能将可变长度的数组原样编组,这是正确的还是还是有办法实现?

c# c arrays struct marshalling
2个回答
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结构动态分配空间,并为数据数组扩展空间

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;

-2
投票

在上述情况下,我肯定会使用SizeParamIndex。


-2
投票

在上述情况下,我肯定会使用SizeParamIndex。

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

祝你好运。>>

© www.soinside.com 2019 - 2024. All rights reserved.