填充用于对齐某些数据类型,即确保某种类型的数据具有某个指定数字的倍数的地址。这在不同型号的 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。
几年前,我阅读了始终将最大元素放在首位以最小化填充的建议,即首先放置长整数,然后是整数,然后是短裤,然后是字符。
如果您要分配数千或数百万个这些,则可以通过此技术节省大量内存。如果你只打算分配一两个,那没什么大不了的。