我有以下 .NET 值类型:
[StructLayout(LayoutKind.Sequential)]
public struct Date
{
public UInt16 V;
}
[StructLayout(LayoutKind.Sequential)]
public struct StringPair
{
public String A;
public String B;
public String C;
public Date D;
public double V;
}
我有将指向值类型的指针传递给非托管代码的代码,以及通过调用 System.Runtime.InteropServices.Marshal.OffsetOf 发现的偏移量。非托管代码正在填充 Date 和 double 值。
为 StringPair 结构报告的偏移量正是我所期望的:0、8、16、24、32
我在测试函数中有以下代码:
FieldInfo[] fields = typeof(StringPair).GetFields(BindingFlags.Instance|BindingFlags.Public);
for ( int i = 0; i < fields.Length; i++ )
{
int offset = System.Runtime.InteropServices.Marshal.OffsetOf(typeof(StringPair), fields[i].Name).ToInt32();
Console.WriteLine(String.Format(" >> field {0} @ offset {1}", fields[i].Name, offset));
}
哪个打印出这些偏移量。
>> field A @ offset 0
>> field B @ offset 8
>> field C @ offset 16
>> field D @ offset 24
>> field V @ offset 32
然后我有一些测试代码: foreach (StringPair pair in pairs) { Date d = pair.D; 双 v = 对.V; ...
在调试器中具有以下与之关联的汇编程序:
Date d = pair.D;
0000035d lea rax,[rbp+20h]
00000361 add rax,20h
00000367 mov ax,word ptr [rax]
0000036a mov word ptr [rbp+000000A8h],ax
00000371 movzx eax,word ptr [rbp+000000A8h]
00000378 mov word ptr [rbp+48h],ax
double v = pair.V;
0000037c movsd xmm0,mmword ptr [rbp+38h]
00000381 movsd mmword ptr [rbp+50h],xmm0
它在偏移量 32 (0x20) 处加载 D 字段,在偏移量 24 (0x38-0x20) 处加载 V 字段。JIT 改变了顺序。Visual Studio 调试器也显示了这种倒序。
为什么!?我一直在拔头发,试图看看我的逻辑哪里出了问题。如果我在结构中交换 D 和 V 的顺序,那么一切正常,但是此代码需要能够处理其他开发人员定义了结构的插件架构,并且不能期望他们记住神秘的布局规则。