c# - 编码(marshal)包含可变长度数组的 C 结构

标签 c# c arrays struct marshalling

我想将具有可变长度数组的 C 结构编码回 C#,但到目前为止,除了指向结构的指针和指向 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 不能在上面的外部函数中获取托管类型的地址、获取其大小或声明指向托管类型的指针

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

    public float[] data;
}

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

最佳答案

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

但如果你知道大小,它会像下面这样:

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;

关于c# - 编码(marshal)包含可变长度数组的 C 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21798986/

相关文章:

c# - Oracle 号码映射 (ODP.NET)

C - printf 输出根据后续代码而变化

c - 从链表中删除项目导致段错误

javascript - 从特定日期获取天数

java - 循环访问对象数组并访问特定的键/值字段

c# - 如何使用 System.Net.Mail 向电子邮件添加附件?

c# - 将匿名集合放入类中

Javascript 将 localStorage getItem 字符串转换为数组

c# - 为什么我不能使用 Global.asax.cs 中 Models 文件夹中的类?

c - 将多个值返回到C中的线程时出错