C# x64上存在TypeLoadException,但在具有structlayouts的x86上没有问题
如果要查看实际异常,需要64位计算机。我创建了一些虚拟类,这就是问题所在C# x64上存在TypeLoadException,但在具有structlayouts的x86上没有问题,c#,.net,x86,64-bit,C#,.net,X86,64 Bit,如果要查看实际异常,需要64位计算机。我创建了一些虚拟类,这就是问题所在 [StructLayout(LayoutKind.Sequential, Pack = 1)] public class InnerType { char make; char model; UInt16 series; } [StructLayout(LayoutKind.Explicit)] public class OutterTyp
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class InnerType
{
char make;
char model;
UInt16 series;
}
[StructLayout(LayoutKind.Explicit)]
public class OutterType
{
[FieldOffset(0)]
char blah;
[FieldOffset(1)]
char blah2;
[FieldOffset(2)]
UInt16 blah3;
[FieldOffset(4)]
InnerType details;
}
class Program
{
static void Main(string[] args)
{
var t = new OutterType();
Console.ReadLine();
}
}
如果在64 clr上运行此命令,则会收到类型加载异常
System.TypeLoadException was unhandled
Message="Could not load type 'Sample.OutterType' from assembly 'Sample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 4 that is incorrectly aligned or overlapped by a non-object field."
如果我强制目标cpu为32,它工作正常
此外,如果我将InnerType从类更改为结构,它也可以工作。有人能解释一下发生了什么或我做错了什么吗
谢谢如果您想将结构放在其他结构中,而这些结构本身是布局的,那么Uint16可能会出现问题,因为它不符合CLS(请参见此处:)如果您希望它们在不同的位模式下工作,请使用显式大小值(以字节为单位)(或在具有不同包装要求的机器上) 你所说的是“按顺序排列,不要在内部打包,而是在最后使用你喜欢的空间”。 如果不指定大小,则运行时可以随意添加任意大小的空间 它通常拒绝让结构和对象类型重叠的原因是GC例程必须能够自由地遍历活动对象图。在这样做时,它无法知道联合(重叠)字段作为对象引用或原始位(例如int或float)是否有意义。由于它必须遍历所有活动对象引用才能正确运行,因此它将遍历“随机”位,这些位可能指向堆中的任何位置(或堆外),就好像它们在您知道之前是引用一样,这是一般保护错误 由于根据运行时,32/64引用将占用32或64位,因此您必须使用Explict,仅将引用与引用合并,值类型与值类型合并,确保引用类型与两个目标平台的边界对齐(注意:依赖于运行时,请参见下文),并执行以下操作之一:
[StructLayout(LayoutKind.Explicit)]
public struct Foo
{
[FieldOffset(0)]
public byte padding;
[FieldOffset(1)]
public string InvalidReference;
}
public static void RunSnippet()
{
Foo foo;
foo.padding = 0;
foo.ValidReference = "blah";
// Console.WriteLine(foo); // uncomment this to fail
}
ECMA规范中有相关详细信息,请参见第16.6.2节,该节要求对齐本机大小值,包括&。注意,如果需要,存在未对齐前缀指令来解决此问题
但是,在mono上(OSX intel和Win32 intel 32位),上述代码都能正常工作。要么运行时不尊重布局并以静默方式“更正”内容,要么允许任意对齐(在这方面,历史上它们不如MS运行时灵活,这令人惊讶)。
mono生成的CLI中间形式不包含任何.unaligned指令前缀,因此它似乎不符合规范
这将教会我只检查mono。这里关于重叠类型的部分有误导性。问题是.Net引用类型必须始终在指针大小边界上对齐。您的并集在x86中工作,因为字段偏移量是4字节,这是32位系统的指针大小,但在x64上失败,因为它必须有偏移量8的倍数。如果在x86平台上将偏移量设置为3或5,则会发生相同的情况
编辑:对于怀疑者-我在internet上找不到现成的参考资料,但请查看第175页。我还注意到,您正在将您的字符数据类型打包为1字节。在.NET中,字符类型的大小为2字节。我无法验证这是否是实际问题,但我会再次检查。我遇到了同样的问题,并且非常讨厌d我在MSDN上找不到关于这个主题的明确参考。在阅读了这里的答案后,我开始关注.NET中x86和x64的差异,并发现了以下内容:。这里他们明确指出,指针在x86上是4字节,在x64上是8字节。希望这对其他人有所帮助 顺便说一句,这里有许多关于堆栈溢出的相关问题。我将添加其中两个,它们提到了其他有趣的事情