为什么只有 "char" 类型成员的结构中没有填充?
Why is there no padding in the structure for only "char" type members?
我在结构中只声明了 char
类型成员。
#include <stdio.h>
struct st
{
char c1;
char c2;
char c3;
char c4;
char c5;
};
int main() {
struct st s;
printf("%zu\n", sizeof(s));
return 0;
}
输出: [Live Demo]
5
那么,为什么只有 char
类型成员的结构没有填充?
填充是为了强制执行对齐要求。如果成员位于可被其大小整除的地址,则称该成员对齐(与其大小)。
在您的示例中不需要填充,因为 st
结构的所有成员都已经与其大小对齐,即:st
的每个成员的地址已经可以被整除它的大小。所有成员都是char
类型,char
的大小是1。如果成员的大小是 1,则该成员始终与其大小对齐,因为任何地址都可以被 1.
整除
某些类型在正确对齐时具有更好的 performance/stability 等。当此类变量后面有其他变量使其起始位置为 "not well-aligned" 时,编译器可能会决定添加填充以便对齐顺利。这都是可选的,当你只有字节时当然没有必要 (char
).
如果您编写这样的结构,您将更有可能观察到填充:
struct pad{
int8_t a;
int64_t b;
};
assert(sizeof(struct pad) == 16);
其内存布局应该是这样的:
|---|-------|---------|
| 1 | 7 | 8 |
|---|-------|---------|
byte|padding|64-bit int
话又说回来,不需要对齐字节,因为它们是最小的存储单位。
结构中的填充存在 (大部分) 以强制 个人 成员与其 基本对齐方式对齐要求,即(C11 3.2p1):
requirement that objects of a particular type be located on storage boundaries with addresses that are particular multiples of a byte address
结构中间和末尾的填充用于确保即使在这些结构的数组中,每个成员仍将根据它们的对齐方式对齐要求。 C11 6.2.8p1:
Complete object types have alignment requirements which place restrictions on the addresses at which objects of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type: stricter alignment can be requested using the _Alignas keyword.
现在,所有其他类型的对齐要求都是实现定义的,但有一点是隐含的:因为对齐要求在 size_t
中表示; sizeof (char)
为 1,指向字符类型的指针可用于寻址其他类型中的每个单独字符,字符类型的基本对齐要求不能超过 1。令人惊讶的是,C 标准中并未明确说明全部;它只有这个模糊的措辞 (C11 6.2.8p6):
The types char
, signed char
, and unsigned char
shall have the weakest alignment requirement.
由于char
的对齐最多为1,编译器不需要添加任何填充,因为即使结构刚好是5字节长,那么即使在数组中,一些结构从奇数地址开始,这些结构的每个成员仍将正确对齐。
我在结构中只声明了 char
类型成员。
#include <stdio.h>
struct st
{
char c1;
char c2;
char c3;
char c4;
char c5;
};
int main() {
struct st s;
printf("%zu\n", sizeof(s));
return 0;
}
输出: [Live Demo]
5
那么,为什么只有 char
类型成员的结构没有填充?
填充是为了强制执行对齐要求。如果成员位于可被其大小整除的地址,则称该成员对齐(与其大小)。
在您的示例中不需要填充,因为 st
结构的所有成员都已经与其大小对齐,即:st
的每个成员的地址已经可以被整除它的大小。所有成员都是char
类型,char
的大小是1。如果成员的大小是 1,则该成员始终与其大小对齐,因为任何地址都可以被 1.
某些类型在正确对齐时具有更好的 performance/stability 等。当此类变量后面有其他变量使其起始位置为 "not well-aligned" 时,编译器可能会决定添加填充以便对齐顺利。这都是可选的,当你只有字节时当然没有必要 (char
).
如果您编写这样的结构,您将更有可能观察到填充:
struct pad{
int8_t a;
int64_t b;
};
assert(sizeof(struct pad) == 16);
其内存布局应该是这样的:
|---|-------|---------|
| 1 | 7 | 8 |
|---|-------|---------|
byte|padding|64-bit int
话又说回来,不需要对齐字节,因为它们是最小的存储单位。
结构中的填充存在 (大部分) 以强制 个人 成员与其 基本对齐方式对齐要求,即(C11 3.2p1):
requirement that objects of a particular type be located on storage boundaries with addresses that are particular multiples of a byte address
结构中间和末尾的填充用于确保即使在这些结构的数组中,每个成员仍将根据它们的对齐方式对齐要求。 C11 6.2.8p1:
Complete object types have alignment requirements which place restrictions on the addresses at which objects of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type: stricter alignment can be requested using the _Alignas keyword.
现在,所有其他类型的对齐要求都是实现定义的,但有一点是隐含的:因为对齐要求在 size_t
中表示; sizeof (char)
为 1,指向字符类型的指针可用于寻址其他类型中的每个单独字符,字符类型的基本对齐要求不能超过 1。令人惊讶的是,C 标准中并未明确说明全部;它只有这个模糊的措辞 (C11 6.2.8p6):
The types
char
,signed char
, andunsigned char
shall have the weakest alignment requirement.
由于char
的对齐最多为1,编译器不需要添加任何填充,因为即使结构刚好是5字节长,那么即使在数组中,一些结构从奇数地址开始,这些结构的每个成员仍将正确对齐。