7

为什么只有当一个结构有多个成员时才添加填充的概念,而当只有一个基本数据类型成员时为什么不包含填充的概念?

如果我们考虑在 32 位机器上

struct 
{
    char a;
} Y;

没有填充,并且 sizeof Y 达到 1 字节。

如果我们考虑这个结构

struct 
{
    char a;
    int b;
} X;

Sizeof X 将是 8bytes 。

我的问题是为什么在第二种情况下要添加填充?如果它是为了让通常以 4 字节的倍数块读取数据的机器进行有效访问,那么为什么在第一种情况下没有填充?

4

4 回答 4

11

在第二种情况下添加了填充,因为在您的机器上,anint与 4 个字节对齐。所以它必须驻留在可以被 4 整除的地址。

0x04   0x05   0x06   0x07   0x08   0x09   0x0A   0x0B

  a      b      b      b      b     

如果不添加填充,则int成员从 address 开始0x05,这是错误的。添加了 3 个填充字节:

0x04   0x05   0x06   0x07   0x08   0x09   0x0A   0x0B

  a   |      padding      |   b      b      b      b

现在int0x08,没关系。

于 2012-10-12T14:48:51.390 回答
3

这不仅仅是效率。

问题不在于访问本身的大小,而在于对齐方式。在大多数机器上,访问未对齐的数据会导致程序崩溃,而在当今的典型机器上,anint将需要在四字节边界上对齐的地址:访问int其地址未在四字节边界上对齐的地址会减慢程序速度相当大,或导致它崩溃。您的第一个结构不包含任何具有对齐考虑的数据,因此不需要填充。你的第二个有一个int,编译器必须确保给定一个数组,所有的int都将正确对齐。这意味着 1) 结构的总大小必须是四的倍数,以及 2)int结构中的偏移量必须是四的倍数。(考虑第一个要求:

struct S
{
    char a;
    int b;
    char c;
};

通常大小为 12,两者后都有填充char。)

在其他语言中,编译器经常对结构进行重新排序,以便具有最严格对齐要求的元素首先出现——对于上面的结构 S,这将导致:

struct S
{
    int b;
    char a;
    char c;
};

并且大小为 8,而不是 12。但是,C 和 C++ 都禁止这样做。

于 2012-10-12T15:02:00.993 回答
0

填充用于对齐某些数据类型,即确保某种类型的数据具有某个指定数字的倍数的地址。这在不同型号的 CPU 之间有所不同,但通常 2 字节整数与 2 的倍数的地址对齐,而 4 字节的整数与 4 的倍数的地址对齐。字符通常不需要对齐。

所以如果一个结构体中只有一个字段,那么只要把结构体放在一个边界合适的地址上,就不需要填充了。而且它总是这样:系统总是将块对齐到所需的最大边界,通常是 4 字节或 8 字节。结构中的一件事将处于适当的边界。仅当您有多个字段时才会出现此问题,因为一个字段的长度可能不会导致下一个字段位于正确的边界。因此,在您的示例中,您有一个 char,当然需要 1 个字节,还有一个 int,需要 4 个字节。假设该结构位于地址 0x1000。然后没有填充,char 将放置在 0x1000,int 放置在 0x1001。但是 int 在 4 字节边界时更有效,因此编译器添加了一些填充字节以将其推送到下一个此类边界 0x1004。所以现在你有 char(1 个字节)、padding(3 个字节)、int(4 个字节),总共 8 个字节。

在这种情况下,您无能为力来改善这种情况。每个结构都将与 4 或 8 字节边界对齐,因此当最小值为 5 字节时,在实践中总是会四舍五入到至少 8。(sizeof 不会显示结构之间的填充,仅显示内部,但内存仍然丢失。)

在其他情况下,您可以通过重新排列字段的顺序来最小化额外填充字节的数量。就像说你有三个字符和三个整数。如果您将结构声明为

struct {char a; int b; char c; int d; char e; int f;}

然后编译器将在第一个 char 之后添加 3 个字节以对齐第一个 int,然后在第二个 char 之后再添加三个字节以对齐第二个 int。这给出了 char (1) + pad (3) + int (4) + char (1) + pad (3) + int (4) + char (1) + pad (3) + int (4) = 24。

但是,如果您声明了它:

struct {char a; char c; char e; int b; int d; int f;}

那么你会得到 char (1) + char (1) + char (1) + pad (1) + int (4) + int (4) + int (4) = 16。

几年前,我阅读了始终将最大元素放在首位以最小化填充的建议,即首先放置长整数,然后是整数,然后是短裤,然后是字符。

如果您要分配数千或数百万个这些,则可以通过此技术节省大量内存。如果你只打算分配一两个,那没什么大不了的。

于 2012-10-12T15:08:13.153 回答
0

Padding是的概念alignment,对于issue of computer efficiency and the speed of the access of the data对齐的数据可以完美地访问fetching cycle of the processor from the addresses where the data are storedit doesn't mean that with out alignment processor doesn't work it only meant for the speed access of the memory对于整数数据类型,它是 4 字节对齐由编译器完成,以便处理器更有效地访问数据。(在 32 位系统中)

在 char 的情况下,数据只需要一个字节,因此不需要对齐,因为每个字节本身都是可用的(in RAM there are pages and each page size is 1 byte)但是对于整数,我们需要 4 个字节并且没有 4 个字节可用,或者没有什么叫做一次访问 4 个字节因此,编译器制定了一个对齐规则,通过该规则整数数据位于正确的地址中。

并通过它可以更快地访问数据。

于 2012-10-12T15:27:46.723 回答