2014-02-15 127 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'在那裏。 –