在结构中包装类型会导致额外的填充

Can wrapping a type in a struct cause additional padding?

本文关键字:填充 结构 包装 包装类 类型      更新时间:2023-10-16

可能重复:
具有单个元素的结构的大小

给定任何类型的A和以下结构:

struct S
{
    A a;
};

是否存在sizeof(S)大于sizeof(A)的情况?

例如,sizeof(std::array<T, n>)可以大于sizeof(T[n])吗?

能够在S中使用A意味着编译器已经了解了A的结构,并且已经向其添加了填充字节。我认为它没有理由向S添加更多的填充,因为它已经对齐了。

虽然结构可以填充,但在我所知道的所有系统上,编译器都会填充,使结构的对齐方式与其成员的最大对齐方式相同。它这样做是为了使结构的数组始终正确对齐。

因此:

struct S 
{
   char a;
} // Size 1, no padding
struct S2 
{
   unsigned int a;
   char b;
} // Size 8, 3 bytes padding (assuming 32 bit integer)

编辑:请注意,编译器还可以添加内部填充,以保持数据的正确对齐。

C/C++标准没有指定任何这些细节。您想要的是运行系统的C ABI(应用程序二进制接口(,它应该指定结构的默认布局(编译器可以选择覆盖它,如果他们认为合适的话,另请参阅#pragma pack(。例如,请参阅X86_64 ABI第13页,其中指出:

骨料和工会结构和工会假设他们最严格的组成部分。每个成员都被分配到具有适当对准的最低可用偏移。尺寸任何对象的对齐总是该对象对齐的倍数。数组除了局部或全局长度至少为16字节或C99可变长度的数组变量数组变量始终具有至少16个字节的对齐。结构和并集对象可能需要填充以满足大小和对齐要求约束。任何填充的内容都是不确定的。

相关文本为5.3.3/2"应用于类时,结果是该类对象中的字节数,包括在数组中放置该类型对象所需的任何填充。">

允许一个实现添加额外的字节用于数组绑定检查(例如"this is the 5th array member out of a total of 12",因为这在这里允许的余地内,并且没有被任何其他要求明确禁止

(据推测,该实现还将为不属于数组的结构存储"1选1"指示;在C++中,类型SS[1]是完全可交换的(

ISO/IEC 14882(10/2008(1.8.5:

除非是位字段(9.6(,否则派生最多的对象应具有非零大小,并应占据一个或多个字节的存储。基类子对象的大小可能为零。

这意味着结构的大小为1,尽管"所有数据成员"(没有(的大小为零,零长度的位字段也是如此(不过,根据9.6.2,这必须是未命名位字段(
但两者都不适用,因为您没有要求一个空的结构,并且您的成员命名的(所以它不能为零长度(。

如果您的a成员的类型为void,则情况类似,但3.9.5不允许("[…]void类型是不完整类型(3.9.1(。对象不应定义为具有不完整类型">(。

简而言之,正如你所说,你最感兴趣的是标准中所说的:不,标准没有明确定义这种情况。

然而,它也不禁止编译器添加填充或应用对齐,大多数编译器默认情况下会将结构填充/对齐到机器字大小(除非另有明确说明(。

结构可以被填充(编译器可以做任何他们喜欢的事情,例如将六个八位字节的类型填充到八个以与页面边界对齐(。不过这不太可能发生。

std::array会更大,因为它在类中存储了一些额外的信息,比如数组的长度在自动驾驶仪上打字;不假思索地阅读std::vector。

如果A是一个字节,则结构将与最近的边界对齐。相反,如果A小于边界,那么是的,它会更大。EX RGB的结构与RGBA的结构大小相同。

我没有可以做到这一点的示例代码。你必须转储内存并查看漏洞。如果你假设所有东西都是大小对齐的,并将一个结构投射到一堆内存中,那么你就会得到坏数据。这就是为什么WAD有用于对齐的填充。随着你的作文变得越来越复杂,编译器关闭漏洞的能力就会减弱。最终会引入填充,任何对内存布局的假设都会变得越来越错误。