考虑:

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

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

结构尺寸分别为12和8。

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

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


当前回答

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

处理器以一定大小(字)的“块”读取内存。假设处理器字有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的计算机上处理大量数据(可以使用交换空间,但速度要慢得多)。您可以在程序中排列变量,直到完成最少的填充(这在其他一些回答中得到了很好的例子),但如果这还不够,您可以显式地禁用填充,这就是打包。

其他回答

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

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

在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的计算机上处理大量数据(可以使用交换空间,但速度要慢得多)。您可以在程序中排列变量,直到完成最少的填充(这在其他一些回答中得到了很好的例子),但如果这还不够,您可以显式地禁用填充,这就是打包。

只有当你告诉编译器显式地对结构进行打包时,才会进行结构打包。你看到的是填充。您的32位系统正在填充每个字段以字对齐。如果您告诉编译器打包结构,它们将分别为6和5字节。但是不要这样做。它不可移植,使编译器生成的代码更慢(有时甚至有bug)。

填充将结构成员对齐到“自然”地址边界——例如,int成员将有偏移量,在32位平台上是mod(4) == 0。默认情况下,填充是开启的。它在你的第一个结构中插入以下“间隙”:

struct mystruct_A {
    char a;
    char gap_0[3]; /* inserted by compiler: for alignment of b */
    int b;
    char c;
    char gap_1[3]; /* -"-: for alignment of the whole struct in an array */
} x;

另一方面,打包可以防止编译器进行填充-这必须显式地请求-在GCC下,它是__attribute__((__packked__)),因此如下:

struct __attribute__((__packed__)) mystruct_A {
    char a;
    int b;
    char c;
};

会在32位架构上产生大小为6的结构。

不过需要注意的是,在允许未对齐内存访问的体系结构(如x86和amd64)上,未对齐内存访问速度较慢,并且在严格对齐的体系结构(如SPARC)上是明确禁止的。

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

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

#pragma pack(n)

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

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

一般采用填料结构

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