Расположение.NET оценивает тип в памяти

У меня есть следующие типы значения.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;
}

У меня есть код, который передает указатель на тип значения к неуправляемому коду, наряду со смещениями, обнаруженными путем вызова Системы. Время выполнения. InteropServices. Маршал. OffsetOf. Неуправляемый код заполняет Дату и дважды оценивает.

Смещения, о которых сообщают для структуры 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 в парах) {Дата d = пара. 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 

Это загружает поле D при смещении 32 (0x20) и V полей при смещении 24 (0x38-0x20). JIT менял порядок. Отладчик Visual Studio показывает этот инвертированный порядок также.

Почему!? Я вытягивал волосы, пытаются видеть, где моя логика идет не так, как надо. Если я подкачиваю порядок D, и V в структуре затем все работает, но этот код должен смочь иметь дело со сменной архитектурой, где другие разработчики определили структуру, и они, как могут ожидать, не будут помнить тайные правила макета.

13
задан Abel 4 April 2012 в 13:33
поделиться

2 ответа

The info you get from the Marshal class is only relevant if the type actually gets marshaled. The internal memory layout of a managed structure is not discoverable through any documented means, other than peeking at the assembly code perhaps.

Which means the CLR is free to reorganize the layout of the structure and optimize the packing. Swapping the D and V fields makes your structure smaller due the alignment requirements of a double. It saves 6 bytes on your 64-bit machine.

Not sure why this would be an issue for you, it shouldn't be. Consider Marshal.StructureToPtr() to get the structure laid-out the way you want it.

12
ответ дан 1 December 2019 в 21:12
поделиться

Если вам нужен явный макет ... используйте явный макет ...

[StructLayout(LayoutKind.Explicit)]
public struct StringPair
{
    [FieldOffset(0)] public String A;
    [FieldOffset(8)] public String B;
    [FieldOffset(16)] public String C;
    [FieldOffset(24)] public Date D;
    [FieldOffset(32)] public double V;
}
14
ответ дан 1 December 2019 в 21:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: