次の .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
次に、いくつかのテスト コードを用意します。ダブル 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 の順序を交換すると、すべてが機能しますが、このコードは、他の開発者が構造体を定義したプラグイン アーキテクチャを処理できる必要があり、難解なレイアウト ルールを覚えているとは期待できません。