2012-05-05 30 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]