2012-05-05 71 views
3

我有一個結構,它有一個非重疊字段報告爲重疊。編組LayoutKind.Explicit結構與重疊失敗發佈版本

[FieldOffset(8)] 
Int32 X; 

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] 
[FieldOffset(12)] 
string Y; 

[FieldOffset(28)] 
int Z; 

報告的錯誤是:

未能加載類型「XXX」 ...它包含的物場在偏移12被不正確地對準或由非對象場重疊。

它僅在發佈配置(TRACE,DEBUG標誌和不安全的代碼被啓用,優化被關閉)時發生,猜測 - 它會發生什麼?

UPD:感謝@svick。確認x64構建不是人們想要的編組。

+0

你是否在StructLayout屬性中指定了字符集?正如在http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.charset.aspx?如果不是這樣,我認爲在構建之間可能會出現一些奇怪的字符集切換,因爲該結構對於單字節字符而不是寬字符是正確的 – tyranid

+0

您可以使用'LayoutKind.Sequential'而不是'LayoutKind.Explicit',並刪除'FieldOffset '屬性?這並不總是可能的,但如果在這種情況下可能的話,它可能會避免整個問題。 – hvd

回答

4

首先,發佈配置與此無關。影響它的是平臺目標:如果將其設置爲x64,則會得到此異常,但如果將其設置爲x86,則它將正常工作。

認爲這種現象的原因是,FieldOffset用於在管理存儲(即使文檔沒有說明這一點)指定struct的佈局,但MarshalAs未在託管內存使用。

因此,託管內存中的對象包含偏移量爲12的引用。由於所有引用都必須在.Net中對齊(在32位應用程序中爲4個字節,在64位中爲8個字節),如果將應用程序作爲64位運行,則會發生異常。

所以,問題不是你有重疊字段,而是錯誤信息的另一部分:字段被錯誤地對齊。

簡單的解決方法是將應用程序編譯爲x86。如果這對你不可行,我不知道如何解決這個問題。

0

我認爲系統中8個字節的數據字段默認對齊。 Y必須使用偏移量16。

5

註釋@ svick的正確答案,這裏的問題是您的結構聲明違反了CLR使對象分配爲原子的硬性承諾。這不能在64位模式下工作,偏移量爲12,對象指針可以跨越緩存行的末尾。訪問這樣一個錯位的成員總是需要兩次讀取或寫入,並且永遠不會是原子的。我認爲它實際上是CLR類型驗證程序中的一個錯誤,但這不會幫助你克服這個問題。

當然,您正在使用32位代碼進行互操作,並且您已正確更改了Debug版本的平臺目標設置,但忘記爲發佈版本做這些。這是一個per-config設置。輕鬆修復,只需更改發佈配置的設置即可。

如果你真的需要這個在64位模式下工作,那麼你需要聲明它爲fixed char[16]