Diseño del tipo de valor .NET en la memoria
Tengo los siguientes tipos de valor .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;
}
Tengo un código que pasa un puntero a un tipo de valor a un código no administrado, junto con las compensaciones descubiertas al llamar a System.Runtime.InteropServices.Marshal.OffsetOf. El código no administrado está llenando la fecha y los valores dobles.
Las compensaciones que se informan para la estructura StringPair son exactamente lo que yo esperaría: 0, 8, 16, 24, 32
Tengo el siguiente código en una función de prueba:
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));
}
Lo que imprime exactamente estas compensaciones.
>> field A @ offset 0
>> field B @ offset 8
>> field C @ offset 16
>> field D @ offset 24
>> field V @ offset 32
Luego tengo un código de prueba: foreach (par de StringPair en pares) {Fecha d = pair.D; doble v = par.V; ...
Que tiene el siguiente ensamblador asociado con él en el depurador:
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
Está cargando el campo D en el desplazamiento 32 (0x20) y el campo V en el desplazamiento 24 (0x38-0x20). El JIT ha cambiado el orden alrededor. El depurador de Visual Studio también muestra este orden invertido.
¿¡Por qué!? He estado sacándome el pelo tratando de ver dónde está yendo mal mi lógica. Si cambio el orden de D y V en la estructura, entonces todo funciona, pero este código debe poder tratar con una arquitectura de complementos donde otros desarrolladores han definido la estructura, y no se puede esperar que recuerden las reglas de diseño arcano.