2014-02-15 74 views
6

我想编组一个带有可变长度数组的C结构回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风格数组,其中datafloat[]但如果我不改变结构来下面的表格确实得到了在上面的外部函数中,无法获取受管理类型的地址,获取大小或声明指针。

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

    public float[] data; 
} 

Apparently,涉及一种具有编组背面的可变长度数组原来的样子,这是正确的或者是它还有一个方法来实现这一点是不可能的?

+0

您可以轻松地将数组作为参数传递。任何你不这样做的理由?你为什么使用'unsafe'? –

+0

你能详细说明一下吗?事情是当我指定MarshalAs.Struct调用的作品,但返回的结构是垃圾(长度不正确),所以我想它不能正常工作。所以现在,唯一的工作是返回一个struct指针并手动访问'data'中的项。关于不安全的声明,我只是忘了删除它。 – Aybe

+0

你不能在一个结构体内部有数组,并让编组员完成这项工作。但是你可以将数组作为指针传递并编组。 –

回答

6

简短的回答 你不能封送可变长度数组的数组,因为如果不知道大小,互操作编组服务不能元帅数组元素

但如果你知道它的大小将是象下面这样:

int arr[15] 

,你将能够调集这样的:

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

,如果你不知道数组的长度d这是你想要 什么,你可以将其转换为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); 

计算应该b的数据数组字段的偏移量向在一个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; 
+0

您还没有看过该问题的标题。 – Aybe

+0

我读了,我说你不能这样做:)。如果你不喜欢我的回答,我可以删除它 –

+0

如果我可以提前知道大小,那么我不会问这个问题:-) – Aybe

-1

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

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

祝你好运。

+1

不幸的是,'SizeParamIndex'仅适用于直接作为参数传递的数组,而不适用于结构中的数组。这必须[手动完成](https://stackoverflow.com/a/22811847/1925996)。 – piedar

+0

@piedar真的吗?这很不幸,我很惊讶。根据[this](https://msdn.microsoft.com/en-us/library/eshywdt7(v = vs.110).aspx),在“声明原型”下,你可以使用' SizeConst'在那里。 –