C# 包含guid的结构上的Marshal.SizeOf提供额外字节

C# 包含guid的结构上的Marshal.SizeOf提供额外字节,c#,struct,size,marshalling,guid,C#,Struct,Size,Marshalling,Guid,我有几个具有顺序布局的结构: struct S1 { Guid id; } struct S2 { Guid id; short s; } struct S3 { Guid id; short s; short t; } 对上述结构类型调用Marshal.SizeOf, 我得到: 我的问题是为什么S2的大小是20而不是18。只有当结构中有Guid时,这个问题才会出现 抱歉,无法从msdn中找到任何有用的信息。我知道Marshal.SizeOf给出了类型将在内存中

我有几个具有顺序布局的结构:

struct S1
{
  Guid id;
}

struct S2 
{
  Guid id;
  short s;
}

struct S3 
{
  Guid id;
  short s;
  short t;
}
对上述结构类型调用
Marshal.SizeOf
, 我得到:

我的问题是为什么S2的大小是20而不是18。只有当结构中有
Guid
时,这个问题才会出现

抱歉,无法从msdn中找到任何有用的信息。我知道
Marshal.SizeOf
给出了类型将在内存中占用的空间大小,但我想知道为什么它需要额外的2个字节才能使大小为4的倍数

我怎样才能避免这个“问题”

非常感谢

我看不到您在结构定义中使用。因此,您将不知道它们是如何“布置”的。你怎么知道他们有顺序布局


一些来源:我认为这是因为某些项必须在内存中对齐到4字节(或8字节)边界。因此,结构是这个大小的倍数,这样结构的数组都将正确对齐。在包含字符串的64位机器上,强制其为8字节的倍数;GUID似乎只需要4字节的倍数,即使在64位上也是如此。 如果包含GUID的结构的大小不是4字节的倍数,则在这些结构的数组中,某些GUID将不在4字节边界上。
我认为您无法避免“问题”-为什么这是一个问题?

这是因为隐含的[StructLayout]附加到结构上,Pack字段是重要的字段。它指示在编组后如何对齐结构的成员。Pack的默认值为8。这表示大小小于或等于8字节的任何成员都是对齐的。换句话说,一个短的将被对齐到一个偏移量,这个偏移量是2的倍数,一个int到4,一个long或double到8

关键的一点是,在创建结构数组时,对齐应该仍然有效。通过一个简单的示例更容易演示:

using System;
using System.Runtime.InteropServices;

class Program {
    static void Main(string[] args) {
        Console.WriteLine(Marshal.SizeOf(typeof(Example)));
        Console.ReadLine();
    }
}
struct Example {
    public int a;
    public short b;
}
产出:8

a
成员强制增加大小,在结构中添加两个额外的填充字节,以确保在数组中使用结构时,int仍然与4的倍数的偏移对齐。可以通过应用属性更改结果:

[StructLayout(LayoutKind.Sequential, Pack = 2)]
struct Example {
    public int a;
    public short b;
}
产出:6

当在数组中使用结构时,
a
成员现在将错误对齐

回到Guid,您无法从声明中看到它,但它在内部由许多成员组成。第一个是名为
\u a
的私有字段,它是一个int。因此Guid需要4字节对齐。因此,在数组中使用结构时,需要额外的2个填充字节才能使结构正确对齐。S2上需要Pack=1或Pack=2才能获得18个字节


有关结构及其在.NET中的特殊处理方式的更多背景信息。

请看@Hans Passant对结构内存布局的深入介绍。他声称
Marhsal.SizeOf
只能提供猜测。
[StructLayout(LayoutKind.Sequential, Pack = 2)]
struct Example {
    public int a;
    public short b;
}