2010-01-01 21 views
5

我有一個C++結構,看起來像這樣一個結構:不能封送包含一個工會

struct unmanagedstruct 
{ 
    int    flags; 
    union 
    { 
     int    offset[6]; 
     struct 
     { 
      float   pos[3]; 
      float   q[4]; 
     } posedesc; 
    } u; 
}; 

而且我想整理一下它像這樣在C#:

[StructLayout(LayoutKind.Explicit)] 
public class managedstruct { 
    [FieldOffset(0)] 
    public int flags; 

    [FieldOffset(4), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6)] 
    public int[] offset; 

    [StructLayout(LayoutKind.Explicit)] 
    public struct posedesc { 
     [FieldOffset(0), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3)] 
     public float[] pos; 

     [FieldOffset(12), MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)] 
     public float[] q; 
    } 

    [FieldOffset(4)] 
    public posedesc pose; 
} 

然而,當我嘗試將數據加載到我的結構中時,只有偏移量數組的前3個元素在那裏(數組的長度爲3)。我可以證實他們的價值觀是正確的 - 但我仍然需要其他3個要素。我做了什麼明顯錯誤?

我使用這些功能加載結構:

private static IntPtr addOffset(IntPtr baseAddress, int byteOffset) { 
    switch (IntPtr.Size) { 
     case 4: 
      return new IntPtr(baseAddress.ToInt32() + byteOffset); 
     case 8: 
      return new IntPtr(baseAddress.ToInt64() + byteOffset); 
     default: 
      throw new NotImplementedException(); 
    } 
} 

public static T loadStructData<T>(byte[] data, int byteOffset) { 
    GCHandle pinnedData = GCHandle.Alloc(data, GCHandleType.Pinned); 
    T output = (T)Marshal.PtrToStructure(addOffset(pinnedData.AddrOfPinnedObject(), byteOffset), typeof(T)); 
    pinnedData.Free(); 
    return output; 
} 

加載例如:

managedstruct mystruct = loadStructData<managedstruct>(buffer, 9000); 

讓我知道如果你需要更多的信息。

+1

編組代碼應該如何知道何時將聯合編組爲「int []」或「float []」?它應該爲每個數組元素選擇,還是總是一個或另一個? – 2010-01-01 00:32:55

回答

1

我不是100%確定這一點,但我相信聯盟意味着兩個成員都使用相同的內存。在C++結構的情況下,int []或posedesc結構。所以結構的大小將是sizeof(int)+ sizeof(posedisc)。意思是,聯合並不意味着你將擁有一個int []和一個posedisc,你將擁有共享的內存,這些內存可以是C++中的那些類型中的任何一種,但是隻有一種或另一種在受管理的域中。

所以我認爲你可能需要兩個託管結構,一個有偏移,另一個有posedisc。你可以在你的LoadStruct調用中選擇一個或另一個。或者,您可以創建一個字節[]字段,並計算將這些字節轉換爲所需類型的屬性。

0

可能導致問題的原因可能是在C++中,int的大小取決於體系結構。

換句話說,在某些情況下,C++結構中的offset數組實際上可能是64位值的數組。

現在,在您的C#結構中,無論何時使用MarshalAs屬性,都不會指定ArraySubType參數。

根據文檔,當您省略ArraySubType時,應該根據託管數組的類型對結構進行編組,但可能是因爲C++結構中的offset數組沒有擴展accros 48個字節,而不是24,正在造成你遇到的問題。

我的建議是嘗試改變所有intlong在C++結構,以確保尺寸始終是相同的,而且在所有MarshalAs屬性添加ArraySubType參數數組。

+0

「長」的大小也取決於體系結構。我建議'int32_t'或任何其他固定大小的類型'stdint.h'。 – 2012-10-08 15:51:20

0

均田遲到了,但我最好的猜測是,你offset數組被通過pos陣列覆蓋時編組到達現場,而這將是參考是被覆蓋,而不是實際的元素。因此,offset將始終爲3(並嘗試GetType就可以了,它應該返回Single[]。這就是你得到的重疊引用)。

因此,無論您是否可以刪除q並將pos的大小設置爲7,也可以使用fixed數組(儘管我不確定它將如何編組)。

相關問題