3

我有一个结构,它有一个报告为重叠的非重叠字段。

[FieldOffset(8)]
Int32 X;

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

[FieldOffset(28)]
int Z;

报告的错误是:

无法加载类型“XXX”...它包含偏移 12 处的对象字段,该对象字段未正确对齐或被非对象字段重叠。

它只发生在发布配置中(启用了跟踪、调试标志和不安全代码,关闭了优化),猜测 - 它会发生什么?

UPD:感谢@svick。确认 x64 构建不是人们想要的编组。

4

3 回答 3

5

注释@svick 的正确答案,这里的问题是您的结构声明违反了 CLR 使对象分配是原子的硬承诺。这不能在 64 位模式下工作,偏移量为 12 时,对象指针可以跨越高速缓存行的末尾。访问这样一个未对齐的成员总是需要两次读取或写入,并且永远不会是原子的。我认为这实际上是 CLR 类型验证器中的一个错误,但这不会帮助您克服这个难题。

当然,您这样做是为了与 32 位代码互操作,并且您正确更改了调试版本的平台目标设置,但忘记为发布版本这样做。这是每个配置的设置。轻松修复,只需更改发布配置的设置即可。

如果你真的需要它在 64 位模式下工作,那么你需要将它声明为fixed char[16]

于 2012-05-05T13:04:31.757 回答
5

首先,Release 配置与此无关。影响它的是平台目标:如果将其设置为 x64,则会出现此异常,但如果将其设置为 x86,它将正常工作。

认为这种行为的原因FieldOffset是用于指定struct托管内存中的布局(即使文档没有这样说),但MarshalAs不在托管内存中使用。

因此,托管内存中的对象包含偏移量 12 处的引用。由于所有引用都必须在 .Net 中对齐(在 32 位应用程序中对齐 4 个字节,在 64 位应用程序中对齐 8 个字节),您会得到异常如果您将应用程序作为 64 位运行。

因此,问题不在于您有重叠的字段,而是错误消息的另一部分:该字段未正确对齐。

简单的解决方法是将应用程序编译为 x86。如果这对你来说不可能,我不知道如何解决这个问题。

于 2012-05-05T11:33:13.420 回答
0

我认为系统中数据字段的默认对齐方式为 8 个字节。您必须为 Y 使用偏移 16。

于 2012-05-05T11:32:59.577 回答