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

Ayb*_*ybe 8 c c# arrays struct marshalling

我想将一个带有可变长度数组的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;
Run Code Online (Sandbox Code Playgroud)

管理代表:

[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);
Run Code Online (Sandbox Code Playgroud)

我想是有一个.NET风格数组,其中datafloat[],但如果我做的结构改变为下面我得到的形式不能取的地址,获取的大小,或宣布一个指向托管类型 的上面的外部功能.

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

    public float[] data;
}
Run Code Online (Sandbox Code Playgroud)

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

Sad*_*ida 8

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

但如果您知道它的大小,它将如下所示:

int arr[15]
Run Code Online (Sandbox Code Playgroud)

你将能够像这样编组它:

[MarshalAs(UnmanagedType.LPArray, SizeConst=15)] int[] arr
Run Code Online (Sandbox Code Playgroud)

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

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

    public int[] data;
}
Run Code Online (Sandbox Code Playgroud)

另一个如下:

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

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

private static int[] ReturnIntArray()
{
    int [] myInt = new int[30];

    for (int i = 0; i < myInt.length; i++)
    {
        myInt[i] = i + 1;
    }

    return myInt;
}
Run Code Online (Sandbox Code Playgroud)

实例化第一个结构

fvec_t1 instance = new fvec_t1();
instance.whatever=10;
instance.data= ReturnIntArray();
Run Code Online (Sandbox Code Playgroud)

实例化第二个结构

fvec_t2 instance1 = new fvec_t2();

instance1.whatever = instance.whatever
Run Code Online (Sandbox Code Playgroud)

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

IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(fvec_t2)) + Instance.data.Length);
Run Code Online (Sandbox Code Playgroud)

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

Marshal.StructureToPtr(instance1, ptr, true);
Run Code Online (Sandbox Code Playgroud)

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

int offset = Marshal.SizeOf(typeof(fvec_t2));
Run Code Online (Sandbox Code Playgroud)

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

IntPtr address = new IntPtr(ptr.ToInt32() + offset);
Run Code Online (Sandbox Code Playgroud)

将数据复制到ptr

Marshal.Copy(instance.data, 0, address, instance.data.Length);
Run Code Online (Sandbox Code Playgroud)

打电话

bool success = dllfunction(ptr);

Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
Run Code Online (Sandbox Code Playgroud)

  • 为什么要分配`Marshal.SizeOf(typeof(fvec_t2))+ Instance.data.Length`?`int`类型不是1字节长度. (3认同)