首页 > 代码库 > c++中类对象的内存对齐
c++中类对象的内存对齐
很多C++书籍中都介绍过,一个Class对象需要占用多大的内存空间。最权威的结论是:
*非静态成员变量总合。(not static)
*加上编译器为了CPU计算,作出的数据对齐处理。(c语言中面试中经常会碰到内存对齐的问题)
*加上为了支持虚函数(virtual function),产生的额外负担。
下面给出几个程序来看一下:
#include <iostream>#include <cstdio>#include <string>using namespace std;class Car1{};void fun1(void){ int size =0; Car1 objCar; size = sizeof(objCar); printf("%s is %d\n","Class Car1 Size",size);}class Car2{private: int nLength; int nWidth;};void fun2(void){ int size = 0; Car2 objCar; size = sizeof(objCar); printf("%s is %d\n","Class Car2 Size",size);}class Car3{private: int nLength; int nWidth; static int sHight;};void fun3(void){ int size =0; Car3 objCar; size =sizeof(objCar); printf("%s is %d\n","Class Car3 Size",size);}class Car4{private: char chLogo; int nLength; int nWidth; static int sHigh;};void fun4(void){ int size =0; Car4 objCar; size = sizeof(objCar); printf("%s is %d\n","Class Car4 Size",size);}class Car5{public: Car5(){}; ~Car5(){};public: void Fun(){};};void fun5(void){ int size =0 ; Car5 objCar; size = sizeof(objCar); printf("%s is %d\n","Class Car5 Size",size);}class Car6{public: Car6(){}; ~Car6(){};public: void Fun(){};private: int nLength; int nWidth;};void fun6(void){ int size = 0; Car6 objCar; size = sizeof(objCar); printf("%s is %d\n","Class Car6 Size",size);}class Car7{public: Car7(){}; virtual ~Car7(){};public: void Fun(){};};void fun7(void){ int size = 0; Car7 objCar; size = sizeof(objCar); printf("%s is %d\n","Class Car7 Size",size);}class Car8{public: Car8(){}; virtual ~Car8(){};public: void Fun(){}; virtual void Fun1(){}};void fun8(void){ int size = 0; Car8 objCar; size = sizeof(objCar); printf("%s is %d\n","Class Car8 Size",size);}int main(){ fun1(); fun2(); fun3(); fun4(); fun5(); fun6(); fun7(); fun8();}
编译:g++ memAlign.cpp -o memAlign
输出结果:
Class Car1 Size is 1Class Car2 Size is 8Class Car3 Size is 8Class Car4 Size is 12Class Car5 Size is 1Class Car6 Size is 8Class Car7 Size is 8
Class Car8 Size is 8
ps:上述编译环境是在mac os下的g++
下面我们具体来分析一下这几个情况:
1、空类、单一继承的空类、多重继承的空类所占空间大小为:1(字节,下同);
2、一个类中,虚函数本身、成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空间的;
3、因此一个对象的大小≥所有非静态成员大小的总和;
4、当类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针vPtr指向虚函数表VTable;
5、虚继承的情况:由于涉及到虚函数表和虚基表,会同时增加一个(多重虚继承下对应多个)vfPtr(virtual function table)指针指向虚函数表vfTable和一个vbPtr(virtual base pointer)指针指向虚基表vbTable,这两者所占的空间大小为:8(或8乘以多继承时父类的个数);
6、在考虑以上内容所占空间的大小时,还要注意编译器下的“补齐”padding的影响,即编译器会插入多余的字节补齐;(请参考《c和指针》)
7、类对象的大小=各非静态数据成员(包括父类的非静态数据成员但都不包括所有的成员函数)的总和+ vfptr指针(多继承下可能不止一个)+vbptr指针(多继承下可能不止一个)+编译器额外增加的字节。
参考:C++虚函数工作原理和(虚)继承类的内存占用大小计算
在VC 6.0中,结果是
Class Car1 Size is 1Class Car2 Size is 8Class Car3 Size is 8Class Car4 Size is 12Class Car5 Size is 1Class Car6 Size is 8Class Car7 Size is 4Class Car8 Size is 4
主要的不同点是:在Car7和Car8,在VC 6.0中虚函数指针占用4个字节,在gcc编译器中占用8个字节。
也可以换一种说法是virtual函数指针在VC下以4字节对齐,在gcc下是8字节对齐,这样解释就比较清楚了。
二、编程实现成员在类或结构体中的偏移量
代码如下所示:
1 #include <cstdio> 2 #include <iostream> 3 #define pos(type,member) (&((type *)0)->member) 4 5 class car{ 6 public: 7 car(){} 8 ~car(){} 9 public:10 virtual void fun(){}11 private:12 int c;13 public:14 void print()15 {16 printf("%x\n",pos(car,c));17 }18 };19 20 int main()21 {22 struct Node{23 int a ;24 char b;25 int c;26 };27 car objCar;28 // printf("%x\n",&((struct Node *)0)->b);29 printf("%x\n",pos(struct Node,b));30 printf("%x\n",pos(struct Node,c));31 // printf("%x\n",pos(class car,c));32 objCar.print();33 return 0;34 }
其中关键的是找到函数能够实现计算成员在类中的偏移量,这里用了宏来实现的。
#define pos(type,member) (&((type *)0)->member)
(从地址0开始的一个type结构体或者类,其成员的地址就是成员所在类或结构体的偏移量)
上述程序的输出结果就是:4 8 8
c++中类对象的内存对齐