“对象的内存 = 所有成员变量的内存大小之和”
但实际上,这个说法只对了一半,还缺了一个关键因素 —— 内存对齐(alignment)和填充(padding)。
✅ 先来个直观例子说明
struct A {
char a; // 1 字节
int b; // 4 字节
};
你可能觉得:1(char)+ 4(int) = 5 字节
但实际上:
std::cout << sizeof(A) << std::endl; // 输出可能是 8
为什么?因为内存对齐。
🧠 为什么会“多出来”?
C++ 中结构体按 最大成员类型的对齐要求 自动插入 padding
对于上面的例子:
成员 | 偏移 | 大小 | 说明 |
---|---|---|---|
a | 0 | 1 | char 占 1 字节 |
pad | 1–3 | 3 | 为了让 int b 对齐到 4 字节地址 |
b | 4 | 4 | int 占 4 字节 |
总计 | 8 | 最终结构体大小是 8 字节 |
📐 内存对齐规则总结
- 每个成员变量的地址必须是它对齐大小的整数倍
- 整个结构体的大小必须是最大对齐单位的整数倍
- 编译器可能在结构体末尾也加 padding 以满足数组连续性
✅ 所以:对象大小 = 成员变量大小之和 + padding
你可以用下面代码来“看”每个成员的偏移:
#include <iostream>
#include <cstddef>
struct A {
char a;
int b;
};
int main() {
std::cout << "sizeof(A) = " << sizeof(A) << std::endl;
std::cout << "offset of a = " << offsetof(A, a) << std::endl;
std::cout << "offset of b = " << offsetof(A, b) << std::endl;
}
📌 如何减少内存?
- 调整成员顺序(小的放后面)
struct B {
int b;
char a;
}; // 比 struct A 紧凑一些
- 使用
#pragma pack(1)
(小心效率降低!)
#pragma pack(push, 1)
struct Packed {
char a;
int b;
};
#pragma pack(pop)
- C++20 可用
[[no_unique_address]]
减少空类占用空间(用于模板)
✅ 总结重点
概念 | 说明 |
---|---|
成员变量内存之和 | 是理论最小值,但通常不等于实际大小 |
实际对象大小 | = 成员内存之和 + 对齐 padding |
查看偏移用什么? | offsetof() 查看字段偏移 |
怎么调小对象大小? | 调整成员顺序、pack 指令、位域/union 等 |