前几天bigo面试,面试官写了个有纯虚函数的类,问了我sizeof是多少……
吃了没用过的亏,特开起了linux虚拟机耍起了sizeof
以下总结
前置知识 基本数据、指针类型大小(单位字节,暂不考虑16位系统)
char 1
short 2
int 4
float 4
double 8
long long 8
long 等于机器位数(32位机器为4,64位机器为8)
指针 等于机器位数
引用 等于所引用数据类型
类的大小基本测试
测试全部在Ubuntu 16.04 64位系统进行
先只来一波数据类型
class C{
int a;
short b;
char c;
double d;
};
按上面的计算,结果应该是4+2+1+8=15。测试结果是16
这里会有内存对齐的情况
我的理解就是,内存按每8个字节分一块(64位机。32位机以4字节分一块),定义在前面的变量会先占用前8字节的内存,a,b,c占了其中4,2,1字节,到d的时候,虽然还剩1字节空间 ,但加上d变量后会超过8字节(来到15字节),因此d不会挤在那个8字节空间里,而会占据下一个8字节,原来多出来的1字节空间是空闲的,但是记在sizeof里(由于class的内存空间从a开始的地址到d结束在内存里地址差是16)。
这个class C在内存里的布局就是这样子
后来一想,真的是因为这个d的存在使得要多占8字节才会sizeof=16吗,于是把double d去掉,只剩前3个变量,再取sizeof
class C{
int a;
short b;
char c;
};
结果是8。(不是7)
那么这个sizeof本身并不是计算最后一个变量的末端地址与第一个变量的首地址之差,因为这个1字节的空闲块也算进去了
那么问题又来了,类内只要有一个变量定义了,sizeof就一定是8字节吗
测试
class C{
int a;
}
答案是4。
不是8诶,后来对所有变量都只单独定义一个,取sizeof都会输出这个变量类型的大小。单一变量不会发生内存对齐
class C{
short a;
char b;
};
输出4。这边char也被对齐了,占了2个空间。基本可以猜想,内存会对齐到类内定义的最大的那个数据类型的size上,类内所有的变量根据定义顺序占的内存都会按照那个size对齐(而不一定是8。有定义了8字节的变量或者定义指针时才会向8对齐)
class C{
int a,b;
short c;
char d;
};
输出12,印证了我的猜想。
class C{
double a;
char c[9];
};sizeof? 17? 18? 24?
类里定义静态变量占不占内存空间?
const变量是占内存空间的。但static呢?这东西的生存期是整个程序运行时,然后变量是全类共用(甚至可以在不定义任何对象时调用这个变量),理论上是不在类里占空间的?
类里面定义一个static变量然后sizeof这个类,如下
class C{
static int a;
};
执行sizeof,答案是1。
呃为啥是1,下面讲空类提一下,但可以肯定的是,static成员变量是不在类里占内存的。(计算sizeof时,忽略static变量)
空类
class C{
};
空类的sizeof是1。根据所查阅的资料,空类在内存中会有1字节的占位符。空类在生成对象的时候也必须要在内存中分配空间,否则无法使用这个对象。
如果往空类里面加函数(普通函数,构造函数,析构函数,static,const等)
class C{
public:
C(){
cout<<"hello C"<<endl;}
~C(){
cout<<"goodbye C"<<endl;}
void print(){
cout<<"print C"<<endl;}
static void s_print(){
cout<<"print static C"<<endl;}
void c_print() const{
cout<<"print const C"<<endl;}
};
上面那堆花里胡哨的函数加进去,sizeof还是1。这些函数只与类有关,与实例无关。(部分资料说根据编译器不同,可能空类的size是一个大于1的数、我目前使用g++做得实验,结果是1,什么编译器的空类会大于1请大佬指点)
但是,如果不是空类,那这1个占位符会失效,内存空间直接就是这些占内存的东西的总和(加上内存对齐的结果)。
虚函数、纯虚函数
如果往类里面加虚函数,结果会有点不一样。
class C{
public:
C(){
cout<<"hello C"<<endl;}
~C(){
cout<<"goodbye C"<<endl;}
virtual void print(){
cout<<"print C"<<endl;}
};
答案是8。虚函数会有一个虚表指针(布局在类的开头),这个虚表指针就占一个指针的空间
但如果有两个虚函数呢?比如说
class C{
public:
C(){
cout<<"hello C"<<endl;}
~C(){