64位系统下C++类内存对齐疑问:char后接string为何padding更少?
C++类内存对齐:char后接string与double的sizeof差异解析
在64位操作系统中,C++编译器通常通过内存填充(padding)优化类成员的内存布局,减少CPU访问周期。但遇到如下两种情况时,sizeof结果出现差异:
- 当类成员为
int i、int j、char name、string s时,预期char name会被填充7字节,使后续string按8字节块读取,sizeof应为40,但实际返回36。 - 当把
string s替换为double d时,char name会被填充7字节,sizeof为24。
对应的测试代码:
#include <iostream> using namespace std; class emp{ public: int i; // 占4字节 int j; // 占4字节 char name; // 预期填充7字节(实际填充3字节) string s; // 占24字节 // double d; // 占8字节(替换string后) }; int main() { emp e1; cout << sizeof(e1); }
核心原因:不同类型的对齐要求不同
内存对齐的核心规则有两条:
- 每个成员的起始地址必须是其对齐要求值的整数倍。
- 整个类的总大小必须是所有成员中最大对齐要求值的整数倍。
1. double的对齐规则(导致sizeof=24)
double是基本类型,在64位系统中对齐要求固定为8字节(等于自身大小),CPU对未对齐的double访问会有严重性能损失,甚至在部分架构下无法访问。int i+int j共占8字节,char name占1字节(起始地址8)。为了让后续double d的起始地址满足8字节对齐,char name后需要填充7字节,让d从地址16开始。- 总大小计算:4+4+1+7+8=24,24是最大对齐值8的整数倍,无需额外填充,最终sizeof为24。
2. std::string的对齐规则(导致sizeof=36)
std::string是自定义类类型,其对齐要求取决于编译器实现和目标架构:- 在x86_64架构下,CPU允许指针的未对齐访问(仅损失少量性能,无访问错误)。因此你的编译器可能将
std::string的对齐要求设置为4字节(而非8字节),以节省内存空间。
- 在x86_64架构下,CPU允许指针的未对齐访问(仅损失少量性能,无访问错误)。因此你的编译器可能将
int i+int j共8字节,char name占1字节(起始地址8)。为了让string s的起始地址满足4字节对齐,char name后仅需填充3字节,让s从地址12开始。- 总大小计算:4+4+1+3+24=36,36是最大对齐值4的整数倍,无需额外填充,最终sizeof为36。
总结差异根源
double作为基本类型,对齐要求是强制的8字节,编译器必须严格按此填充。std::string作为自定义类型,其对齐要求具有灵活性,编译器可在架构允许的前提下,选择更低的对齐值以节省内存,这就是两种场景下sizeof结果不同的核心原因。
内容的提问来源于stack exchange,提问作者archana
相关产品推荐
相关产品推荐

