为什么不管成员的顺序如何,这个结构的大小都是一样的?
Why the size of this structure is same irrespective of the order of the members?
由于 C 中结构的内存对齐是以第一个元素的连续形式完成的,然后是第二个元素,然后是第三个元素,依此类推...以及位填充,那么为什么这个结构的大小是相同的即使重新排列元素:
#include <stdio.h>
int main(void)
{
struct student
{
float c;
int a;
char b;
};
printf("%zu\n", sizeof(struct student));
return 0;
}
输出:
12
对于上面的结构配置,内存对齐看起来像这样吗?:
f f f f i i i i c
_ _ _ _ _ _ _ _ _ _ _
0 1 2 3 4 5 6 7 8 9 10
在您的系统上,int
和 float
数据类型似乎各有 4 个字节;因此,编译器(除非另有说明)将在 4 字节边界上对齐这些类型的结构成员。这就是为什么,如果您将 char b
字段作为 second 成员,那么将在该字段和下一个字段之间添加 3 个字节的 'padding' - 给出结构的总大小为 12 个字节。
但是,编译器也会在结构的末尾添加填充!(三个字节,同样,在 char b
是最后一个字段的情况下。 )
为什么? 好吧,考虑这样的 struct
类型的数组。如果没有 'terminal padding',第二个数组元素的第一个字段将错位——也就是说,它将 而不是 在 4 字节边界上,从而降低从中获得的任何效率'internal' 填充。将您的类型作为嵌套字段包含在内的其他结构也会出现类似问题。
编辑:我无法对 this Wikipedia page 的以下陈述提供太多改进:
It is important to note that the last member is padded with the number
of bytes required so that the total size of the structure should be a
multiple of the largest alignment of any structure member …
看来在您的机器上 int
和 float
都需要 4 个字节。从这个意义上说,它们在 struct
中的位置无关紧要。
但是,char
(通常)只占用 1 个字节,因此您可能想知道 sizeof
为什么 return 9
(4+4+ 1) 原因是 padding.
填充在许多情况下被添加,但最明显的是允许类型对齐(我假设你系统上的 int
和 float
类型在 4 字节上自然对齐边界)。
我认为如果顺序更改为:
struct student
{
float c;
char b;
int a;
};
在此示例中,我们将有 4 个字节 (float
) + 1 个字节 (char
) + 3 个字节(填充)+ 4 个字节 (int
)。即:
struct student
{
float c;
char b;
char padding[3];
int a;
};
但是,在您的原始示例中,我们有:
struct student
{
float c;
int a;
char b;
};
这导致 4 个字节 (float
) + 4 个字节 (int
) + 1 个字节 (char
) + 3 个字节(填充)- 即:
struct student
{
float c;
int a;
char b;
char padding[3];
};
我们仍然在 struct
末尾进行填充的原因是允许数组 (struct student array[32]
)。
如果 struct
末尾没有任何填充,则数组的第二个成员 (array[1]
) 将从偏移量和类型 (float
) 不会在自然的 4 字节边界上正确对齐。
当您声明类型时,编译器将始终添加允许在数组中使用该类型所需的填充(即,当使用 malloc
分配内存时)。
我希望这能回答你的问题。
编辑:
为了澄清我上面没有列出的剩余 struct
中的填充(见评论),它可能看起来像这样(假设编译器正在为类似系统编译代码):
struct student
{
char b;
char padding[3];
float c;
int a;
};
如果 a
也是 char
,我们将在 struct
的两端填充:
struct student
{
char b;
char padding[3];
float c;
char a;
char padding2[3];
};
但是,如果我们重新组织 struct
使字符彼此相邻,它们的填充将不同,因为 char
类型没有 4 字节的自然对齐在这个系统上:
struct student
{
char b;
char a;
char padding[2];
float c;
};
注:
大多数编译器应该支持告诉编译器“打包”结构(忽略类型对齐和填充)的指令......但是,恕我直言,应该非常不鼓励这样做,因为它可能会导致一些 CPU体系结构崩溃并引入不可移植的代码 (see also here)。
编译器对齐字段并填充 struct
的剩余部分,因此如果您构建数组,下一个元素将对齐。
在您的 posted 案例中,字段元素的对齐方式是两个字段 float
和 int
的大小,这两个字段大 4 个字节。因此,编译器在末尾填充结构,以便您定义的类型的下一个数组元素也对齐。这意味着编译器必须在 char
类型字段后添加三个填充元素,即使它位于结构的末尾。
在你 post 的情况下,如果你认为结构是 5 个字节,结构数组的下一个元素将不会对齐,因为 float 和 int 将从 +1
对齐偏移量。
由于 C 中结构的内存对齐是以第一个元素的连续形式完成的,然后是第二个元素,然后是第三个元素,依此类推...以及位填充,那么为什么这个结构的大小是相同的即使重新排列元素:
#include <stdio.h>
int main(void)
{
struct student
{
float c;
int a;
char b;
};
printf("%zu\n", sizeof(struct student));
return 0;
}
输出:
12
对于上面的结构配置,内存对齐看起来像这样吗?:
f f f f i i i i c
_ _ _ _ _ _ _ _ _ _ _
0 1 2 3 4 5 6 7 8 9 10
在您的系统上,int
和 float
数据类型似乎各有 4 个字节;因此,编译器(除非另有说明)将在 4 字节边界上对齐这些类型的结构成员。这就是为什么,如果您将 char b
字段作为 second 成员,那么将在该字段和下一个字段之间添加 3 个字节的 'padding' - 给出结构的总大小为 12 个字节。
但是,编译器也会在结构的末尾添加填充!(三个字节,同样,在 char b
是最后一个字段的情况下。 )
为什么? 好吧,考虑这样的 struct
类型的数组。如果没有 'terminal padding',第二个数组元素的第一个字段将错位——也就是说,它将 而不是 在 4 字节边界上,从而降低从中获得的任何效率'internal' 填充。将您的类型作为嵌套字段包含在内的其他结构也会出现类似问题。
编辑:我无法对 this Wikipedia page 的以下陈述提供太多改进:
It is important to note that the last member is padded with the number of bytes required so that the total size of the structure should be a multiple of the largest alignment of any structure member …
看来在您的机器上 int
和 float
都需要 4 个字节。从这个意义上说,它们在 struct
中的位置无关紧要。
但是,char
(通常)只占用 1 个字节,因此您可能想知道 sizeof
为什么 return 9
(4+4+ 1) 原因是 padding.
填充在许多情况下被添加,但最明显的是允许类型对齐(我假设你系统上的 int
和 float
类型在 4 字节上自然对齐边界)。
我认为如果顺序更改为:
struct student
{
float c;
char b;
int a;
};
在此示例中,我们将有 4 个字节 (float
) + 1 个字节 (char
) + 3 个字节(填充)+ 4 个字节 (int
)。即:
struct student
{
float c;
char b;
char padding[3];
int a;
};
但是,在您的原始示例中,我们有:
struct student
{
float c;
int a;
char b;
};
这导致 4 个字节 (float
) + 4 个字节 (int
) + 1 个字节 (char
) + 3 个字节(填充)- 即:
struct student
{
float c;
int a;
char b;
char padding[3];
};
我们仍然在 struct
末尾进行填充的原因是允许数组 (struct student array[32]
)。
如果 struct
末尾没有任何填充,则数组的第二个成员 (array[1]
) 将从偏移量和类型 (float
) 不会在自然的 4 字节边界上正确对齐。
当您声明类型时,编译器将始终添加允许在数组中使用该类型所需的填充(即,当使用 malloc
分配内存时)。
我希望这能回答你的问题。
编辑:
为了澄清我上面没有列出的剩余 struct
中的填充(见评论),它可能看起来像这样(假设编译器正在为类似系统编译代码):
struct student
{
char b;
char padding[3];
float c;
int a;
};
如果 a
也是 char
,我们将在 struct
的两端填充:
struct student
{
char b;
char padding[3];
float c;
char a;
char padding2[3];
};
但是,如果我们重新组织 struct
使字符彼此相邻,它们的填充将不同,因为 char
类型没有 4 字节的自然对齐在这个系统上:
struct student
{
char b;
char a;
char padding[2];
float c;
};
注:
大多数编译器应该支持告诉编译器“打包”结构(忽略类型对齐和填充)的指令......但是,恕我直言,应该非常不鼓励这样做,因为它可能会导致一些 CPU体系结构崩溃并引入不可移植的代码 (see also here)。
编译器对齐字段并填充 struct
的剩余部分,因此如果您构建数组,下一个元素将对齐。
在您的 posted 案例中,字段元素的对齐方式是两个字段 float
和 int
的大小,这两个字段大 4 个字节。因此,编译器在末尾填充结构,以便您定义的类型的下一个数组元素也对齐。这意味着编译器必须在 char
类型字段后添加三个填充元素,即使它位于结构的末尾。
在你 post 的情况下,如果你认为结构是 5 个字节,结构数组的下一个元素将不会对齐,因为 float 和 int 将从 +1
对齐偏移量。