考虑:
struct mystruct_A
{
char a;
int b;
char c;
} x;
struct mystruct_B
{
int b;
char a;
} y;
结构尺寸分别为12和8。
这些结构是填充的还是包装的?
什么时候进行填充或包装?
考虑:
struct mystruct_A
{
char a;
int b;
char c;
} x;
struct mystruct_B
{
int b;
char a;
} y;
结构尺寸分别为12和8。
这些结构是填充的还是包装的?
什么时候进行填充或包装?
当前回答
填充和填充只是同一事物的两个方面:
包装或对齐是每个成员四舍五入的大小 填充是为匹配对齐而添加的额外空间
在mystruct_A中,假设默认对齐为4,则每个成员以4字节的倍数进行对齐。因为char的大小是1,所以a和c的填充是4 - 1 = 3个字节,而int b不需要填充,因为它已经是4个字节了。它对mystruct_B的工作方式相同。
其他回答
填充规则:
结构体的每个成员都应该位于能被其大小整除的地址。 填充在元素之间或结构的末尾插入,以确保满足此规则。这样做是为了硬件更容易和更有效地访问总线。 结构体末尾的填充是根据结构体最大成员的大小决定的。
规则二: 考虑下面的结构,
如果我们要为这个结构体创建一个数组(包含2个结构体), 结束时不需要填充:
因此,struct的大小= 8字节
假设我们要创建另一个结构体,如下所示:
如果我们要创建这个结构体的数组, 最后需要填充的字节数有两种可能。
A.如果我们在末尾添加3个字节,并将其对齐为int而不是Long:
B.如果我们在末尾添加7个字节并将其对齐为Long:
第二个数组的起始地址是8(i)的倍数。e 24)。 struct的大小= 24字节
因此,通过将结构体的下一个数组的起始地址对齐为最大成员(i。E如果我们要创建这个结构体的数组,第二个数组的第一个地址必须从一个地址开始,该地址必须是该结构体最大成员的倍数。这里是24(3 * 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的计算机上处理大量数据(可以使用交换空间,但速度要慢得多)。您可以在程序中排列变量,直到完成最少的填充(这在其他一些回答中得到了很好的例子),但如果这还不够,您可以显式地禁用填充,这就是打包。
结构填充抑制结构填充,当对齐最重要时使用填充,当空间最重要时使用填充。
一些编译器提供#pragma来抑制填充或将其打包为n个字节。有些公司提供关键字来做到这一点。通常,用于修改结构填充的pragma将采用以下格式(取决于编译器):
#pragma pack(n)
例如,ARM提供了__packed关键字来抑制结构填充。查阅编译器手册了解更多相关信息。
所以一个填充结构是一个没有填充的结构。
一般采用填料结构
为了节省空间 对数据结构进行格式化,以便在网络上传输 协议(这当然不是一个好的实践,因为您需要这样做 处理字节序)
填充将结构成员对齐到“自然”地址边界——例如,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)上是明确禁止的。
这件事没有但是!想要掌握这门学科必须做到以下几点:
细读埃里克·s·雷蒙德所著的《丢失的结构包装艺术》 看一下Eric的代码示例 最后但并非最不重要的是,不要忘记下面关于填充的规则,即结构体的对齐方式与最大类型的对齐方式一致 要求。