在内存中的.NET值类型的布局 [英] Layout of .NET value type in memory

查看:179
本文介绍了在内存中的.NET值类型的布局的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下.NET值类型:

I have the following .NET value types:

[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;
}

我有code,它是传递一个指针的值类型非托管code,同时通过调用System.Runtime.InteropServices.Marshal.OffsetOf发现偏移。非托管code为填充日期和双重价值。

I have code that is passing a pointer to a value type to unmanaged code, along with offsets discovered by calling System.Runtime.InteropServices.Marshal.OffsetOf. The unmanaged code is populating the Date and double values.

这是报告的StringPair结构的偏移量是正是我所期望的:0,8,16,24,32

The offsets that are reported for the StringPair struct are exactly what I would expect: 0, 8, 16, 24, 32

我有以下的code的测试功能:

I have the following code in a test function:

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));
}

打印出究竟这些偏移。

Which prints out exactly these offsets.

 >> field A @ offset 0
 >> field B @ offset 8
 >> field C @ offset 16
 >> field D @ offset 24
 >> field V @ offset 32

我则有一些测试code:             的foreach(StringPair对成对)             {                 日期D = pair.D;                 双V = pair.V;                 ......

I then have some test code: foreach (StringPair pair in pairs) { Date d = pair.D; double v = pair.V; ...

这与它在调试器相关的汇编程序如下:

Which has the following assembler associated with it in the debugger:

               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调试器显示了这个顺序颠倒了。

It is loading the D field at offset 32 (0x20) and the V field at offset 24 (0x38-0x20). The JIT has changed the order around. The Visual Studio debugger shows this inverted order too.

为什么!?我一直在拉我的头发尽量看到我的逻辑是怎么了。如果我换D和第五的秩序结构,然后一切正常,但这code需要能够应对在其他开发人员定义的结构一个插件架构,他们不能指望记得奥术布局规则。

Why!? I've been pulling my hair out try to see where my logic is going wrong. If I swap the order of D and V in the struct then everything works, but this code needs to be able to deal with a plugin architecture where other developers have defined the struct, and they can't be expected to remember arcane layout rules.

推荐答案

您在Marshal类中得到的信息是只有在类型实际上被封有关。一个管理结构的内存布局是不是发现通过任何记录手段,除了偷看大会code可能。

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.

这意味着在CLR是自由重组结构的布局,优化填料。交换为D和V领域作出应有的两倍对齐要求你的结构更小。它可以节省您的64位机上6个字节。

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.

不知道为什么,这将是你的问题,它不应该是。考虑Marshal.StructureToPtr()来获取结构布置的,你想要的方式。

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.

这篇关于在内存中的.NET值类型的布局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆