11

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

struct S1
{
  Guid id;
}

struct S2 
{
  Guid id;
  short s;
}

struct S3 
{
  Guid id;
  short s;
  short t;
}

调用Marshal.SizeOf上述结构类型,我得到:

Size:
S1 = 16, as expected.
S2 = 20, copied an instance to a byte array, it only occupies first 18 bytes.
S3 = 20.

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

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

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

非常感谢!

4

3 回答 3

10

这是因为隐含的 [StructLayout] 附加到结构,Pack字段是重要的。它规定了结构成员在编组后如何对齐。Pack 的默认值为 8。这表示任何小于或等于 8 字节大小的成员都是对齐的。换句话说,short 将与 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,您无法从声明中看到它,但它在内部由许多成员组成。第一个是命名的私有字段_a,它是一个 int。因此,Guid 需要 4 字节对齐。因此,当在数组中使用结构时,需要 2 个额外的填充字节才能正确对齐。您需要在 S2 上使用 Pack=1 或 Pack=2 才能获得 18 个字节。

更多关于结构的背景知识以及在此答案中在 .NET 中处理它们的特殊方式。

于 2012-09-24T21:24:57.170 回答
0

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

于 2012-09-24T21:24:16.177 回答
0

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

一些来源:sizeof() 结构未知。为什么?什么时候应该明确指定一个 StructLayout?

于 2012-09-24T21:10:44.150 回答