当进行编组时,打包是如何工作的?

4

我有这样一个结构:

[StructLayout(LayoutKind.Sequential, Pack = 8)]
unsafe struct MyStruct_t
{
    public UInt32 ulID;
    public fixed Byte xValue[32];
}

然后我运行以下命令来获取大小:

Console.WriteLine("Marshal.SizeOf(typeof(MyStruct_t))= {0}", Marshal.SizeOf(typeof(MyStruct_t)));

答案始终如一。
Marshal.SizeOf(typeof(MyStruct_t))= 36 

我原本期望的是40。我错过了什么吗?在Pack=8的含义上,有些地方我不理解吗?


如果Pack设置为8,则结构体的大小与默认情况下仍然相同,因为ulID字段在4字节边界上对齐,这比Pack字段指定的8字节边界要小。 - Markiian Benovskyi
那么在这种情况下,Pack字段就会被忽略了? - A.B.
1
它决定了运行时何时放弃尝试保持成员对齐,因为它太大了。UInt32占用4个字节,固定缓冲区对齐到1,因为其元素类型是byte。因此,在这两个成员之间永远不需要填充,缓冲区始终正确对齐。在结构体存储在数组中时,末尾的填充用于确保成员仍然对齐。由于总大小恰好是4的倍数,因此也从未需要填充,因此在这种情况下Pack根本不重要。 - Hans Passant
1
但它并不是任意的,它必须始终匹配本地代码中使用的打包方式。对于C或C++编译器来说,8是默认值,如果要使其不同,则需要使用#pragma或奇怪的编译选项(/Zp)。 - Hans Passant
1个回答

4

来自MSDN:

类型实例的字段通过以下规则对齐:

  • 类型的对齐方式是其最大元素的大小 (1、2、4、8 字节等) 或指定的打包大小,以较小者为准

你的 Pack=8,但你的最大尺寸元素是 4 (即 UInt32)。8 和 4 的较小值是 4。

如果你想让你的结构体占用 40 字节,你需要添加 4 个字节的“填充位”。


1
您还可以将属性的Size字段设置为40,以使编译器自动将其填充到40个字节。 - Joe Sewell
2
@JoeSewell 是的,尽管它只会在结尾处添加填充。如果您希望数组在8字节边界上对齐,则需要在字段之间自己添加填充。 - Ron Beyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接