考虑:

struct mystruct_A
{
   char a;
   int b;
   char c;
} x;

struct mystruct_B
{
   int b;
   char a;
} y;

结构尺寸分别为12和8。

这些结构是填充的还是包装的?

什么时候进行填充或包装?


当前回答

填充规则:

结构体的每个成员都应该位于能被其大小整除的地址。 填充在元素之间或结构的末尾插入,以确保满足此规则。这样做是为了硬件更容易和更有效地访问总线。 结构体末尾的填充是根据结构体最大成员的大小决定的。

规则二: 考虑下面的结构,

如果我们要为这个结构体创建一个数组(包含2个结构体), 结束时不需要填充:

因此,struct的大小= 8字节

假设我们要创建另一个结构体,如下所示:

如果我们要创建这个结构体的数组, 最后需要填充的字节数有两种可能。

A.如果我们在末尾添加3个字节,并将其对齐为int而不是Long:

B.如果我们在末尾添加7个字节并将其对齐为Long:

第二个数组的起始地址是8(i)的倍数。e 24)。 struct的大小= 24字节

因此,通过将结构体的下一个数组的起始地址对齐为最大成员(i。E如果我们要创建这个结构体的数组,第二个数组的第一个地址必须从一个地址开始,该地址必须是该结构体最大成员的倍数。这里是24(3 * 8)),我们可以计算出最后所需的填充字节数。

其他回答

这些结构是填充的还是包装的?

它们填充。

最初想到的唯一可能是,如果char和int的大小相同,那么char/int/char结构的最小大小将不允许填充,int/char结构也是如此。

然而,这将要求sizeof(int)和sizeof(char)都为4(以获得12和8的大小)。由于sizeof(char)始终为1的标准保证了整个理论的崩溃。

如果char和int的宽度相同,那么大小将是1和1,而不是4和4。因此,为了得到12的大小,在最终字段之后必须有填充。


什么时候进行填充或包装?

只要编译器实现需要。编译器可以在字段之间和最后一个字段之后(但不能在第一个字段之前)插入填充。

这样做通常是为了性能,因为某些类型在特定边界上对齐时性能更好。甚至有一些架构会在你试图访问未对齐的数据时拒绝运行(即崩溃)(是的,我在看你,ARM)。

您通常可以使用特定于实现的特性(如#pragma pack)来控制打包/填充(这实际上是同一领域的两个极端)。即使您不能在特定的实现中这样做,您也可以在编译时检查代码以确保它满足您的需求(使用标准C特性,而不是特定于实现的东西)。

例如:

// C11 or better ...
#include <assert.h>
struct strA { char a; int  b; char c; } x;
struct strB { int  b; char a;         } y;
static_assert(sizeof(struct strA) == sizeof(char)*2 + sizeof(int), "No padding allowed");
static_assert(sizeof(struct strB) == sizeof(char)   + sizeof(int), "No padding allowed");

如果这些结构中有任何填充,类似这样的东西将拒绝编译。

填充和填充只是同一事物的两个方面:

包装或对齐是每个成员四舍五入的大小 填充是为匹配对齐而添加的额外空间

在mystruct_A中,假设默认对齐为4,则每个成员以4字节的倍数进行对齐。因为char的大小是1,所以a和c的填充是4 - 1 = 3个字节,而int b不需要填充,因为它已经是4个字节了。它对mystruct_B的工作方式相同。

我知道这个问题很老了,这里的大多数答案都很好地解释了填充,但当我自己试图理解它时,我发现对正在发生的事情有一个“视觉”形象是有帮助的。

处理器以一定大小(字)的“块”读取内存。假设处理器字有8字节长。它将把内存看作一个8字节的大行构建块。每当它需要从内存中获取一些信息时,它就会到达其中一个块并获取它。

如上图所示,一个Char(1字节长)在哪里并不重要,因为它将在其中一个块中,只需要CPU处理1个字。

When we deal with data larger than one byte, like a 4 byte int or a 8 byte double, the way they are aligned in the memory makes a difference on how many words will have to be processed by the CPU. If 4-byte chunks are aligned in a way they always fit the inside of a block (memory address being a multiple of 4) only one word will have to be processed. Otherwise a chunk of 4-bytes could have part of itself on one block and part on another, requiring the processor to process 2 words to read this data.

这同样适用于8字节的double,只不过现在它必须在8的倍数内存地址中,以确保它始终在块中。

这里考虑的是8字节的字处理器,但这个概念也适用于其他大小的字。

填充通过填充这些数据之间的间隙来确保它们与这些块对齐,从而提高读取内存时的性能。

然而,正如其他人回答的那样,有时空间比性能本身更重要。也许您正在一台没有太多RAM的计算机上处理大量数据(可以使用交换空间,但速度要慢得多)。您可以在程序中排列变量,直到完成最少的填充(这在其他一些回答中得到了很好的例子),但如果这还不够,您可以显式地禁用填充,这就是打包。

填充规则:

结构体的每个成员都应该位于能被其大小整除的地址。 填充在元素之间或结构的末尾插入,以确保满足此规则。这样做是为了硬件更容易和更有效地访问总线。 结构体末尾的填充是根据结构体最大成员的大小决定的。

规则二: 考虑下面的结构,

如果我们要为这个结构体创建一个数组(包含2个结构体), 结束时不需要填充:

因此,struct的大小= 8字节

假设我们要创建另一个结构体,如下所示:

如果我们要创建这个结构体的数组, 最后需要填充的字节数有两种可能。

A.如果我们在末尾添加3个字节,并将其对齐为int而不是Long:

B.如果我们在末尾添加7个字节并将其对齐为Long:

第二个数组的起始地址是8(i)的倍数。e 24)。 struct的大小= 24字节

因此,通过将结构体的下一个数组的起始地址对齐为最大成员(i。E如果我们要创建这个结构体的数组,第二个数组的第一个地址必须从一个地址开始,该地址必须是该结构体最大成员的倍数。这里是24(3 * 8)),我们可以计算出最后所需的填充字节数。

结构填充抑制结构填充,当对齐最重要时使用填充,当空间最重要时使用填充。

一些编译器提供#pragma来抑制填充或将其打包为n个字节。有些公司提供关键字来做到这一点。通常,用于修改结构填充的pragma将采用以下格式(取决于编译器):

#pragma pack(n)

例如,ARM提供了__packed关键字来抑制结构填充。查阅编译器手册了解更多相关信息。

所以一个填充结构是一个没有填充的结构。

一般采用填料结构

为了节省空间 对数据结构进行格式化,以便在网络上传输 协议(这当然不是一个好的实践,因为您需要这样做 处理字节序)