因为编译器为满足内存对齐要求而插入填充字节:每个成员起始地址须为其对齐值整数倍,结构体总大小须为最大成员对齐值的整数倍,故sizeof结果大于成员字节和。

sizeof计算结构体大小时,为什么结果比成员总和大
因为编译器会对结构体做内存对齐,插入填充字节(padding)使每个成员地址满足其对齐要求。比如 int 通常需 4 字节对齐,char 只需 1 字节,但若它后面跟一个 int,编译器可能在 char 后补 3 字节空隙,让 int 起始地址能被 4 整除。
实际大小 = 成员占用 + 填充字节 + 末尾可能的补齐(结构体整体也要对齐到其最大成员的对齐值)。
- 用
alignof(T)查看类型对齐要求,如alignof(int)通常是 4 - 结构体的对齐值是其所有成员中最大的
alignof值 -
sizeof返回的是对齐后的总字节数,不是“逻辑字段长度之和”
如何验证结构体内部布局和填充位置
最直接的方法是用 offsetof 宏(需 #include <cstddef></cstddef>)检查各成员偏移量:
#include <cstddef>
struct S {
char a;
int b;
short c;
};
// offsetof(S, a) == 0
// offsetof(S, b) == 4 ← 这里已有 3 字节 padding
// offsetof(S, c) == 8 ← int 占 4 字节,short 需 2 字节对齐,刚好接上
// sizeof(S) == 12 ← 结构体整体要对齐到 alignof(int)==4,末尾无需补
- 成员顺序直接影响填充量:把大对齐成员放前面,小的放后面,通常能减少 padding
- 用
#pragma pack(1)可禁用对齐(慎用),此时sizeof才接近成员字节和 - 不同平台或编译器默认对齐策略可能不同,嵌入式或跨平台代码必须显式控制
union 和 struct 混合时 sizeof 怎么算
当结构体含 union 成员时,sizeof 不是简单相加:union 大小取其最大成员的大小(按对齐后尺寸),且 union 本身也参与外层结构体的对齐计算。
立即学习“C++免费学习笔记(深入)”;
例如:
struct U {
char x;
union { int a; double b; };
};
// sizeof(char) == 1
// union 内部:int 是 4 字节(对齐 4),double 通常是 8 字节(对齐 8)
// → union 自身大小为 8,对齐值为 8
// 所以 char x 占 offset 0,union 从 offset 8 开始(x 后补 7 字节)
// sizeof(U) == 16(结构体整体对齐到 8)
- union 的对齐值是其所有成员中最大的
alignof - 结构体中 union 的起始地址必须满足其自身对齐要求
- 不要假设 union 就是“几个变量共享同一块内存”就等于“只占最大成员字节数”——它前面和后面都可能有 padding
容易忽略的陷阱:空结构体、继承、虚函数
C++ 标准规定空结构体(不含成员)的 sizeof 至少为 1,避免地址相同;但带虚函数的类会隐含 vptr 指针(通常 8 字节 on x64),且虚继承还会引入额外指针和对齐调整。
-
struct {} s;→sizeof(s) == 1(不是 0) - 含虚函数的 class:
sizeof包含 vptr,且 vptr 位置不固定(常在开头),影响后续成员偏移 - 多重虚继承可能导致多个 vptr 或 offset 表指针,
sizeof显著增大,且不可仅靠成员推算 - 调试时别只看源码字段,用
offsetof或编译器扩展(如 GCC 的__builtin_offsetof)实测更可靠
对齐和填充不是编译器“多此一举”,而是 CPU 访问效率与硬件约束的体现。手动优化结构体布局前,先确认是否真成了性能瓶颈;盲目 #pragma pack 可能导致未对齐访问崩溃,尤其在 ARM 或 RISC-V 上。


















