C/C++中结构体和类大小

本文在Linux 64位系统下,分析C/C++中结构体和类的大小。结构体分配大小是最大系统支持类型成员的整数倍,采用字节对齐。类大小涉及虚表指针和继承方式,与普通成员变量、虚函数、继承有关,与静态成员变量和成员函数无关。

结构体大小

        首先看一下代码案例,该运行环境为Linux下的64位操作系统。代码 test.c 如下:

/*******************
Author : lijd
data   : 2019-07-11
********************/
#include <stdio.h>

struct A{
	int 	a;
	char 	b;
	short 	c;
}T_A;

struct B{
	char 	b;
	int 	a;
	short 	c;
}T_B;

struct C{
	char 	b;
	short 	c;
	int 	a;
}T_C;

struct D{
	short	d;
	char 	b;
	short 	c;
	int 	a;
}T_D;

struct E{
	char 	b;
	struct A	t_d;
	short 	c;
	int 	a;
}T_E;

struct F{
	char 	b;
	int 	A_a;
	char 	A_b;
	short 	A_c;
	short 	c;
	int 	a;
}T_F;


int main()
{
	printf("sizeof(int) = %d, sizeof(char) = %d, sizeof(short) = %d\n", sizeof(int), sizeof(char), sizeof(short));
	
	printf("sizeof(T_A) = %d, sizeof(T_B) = %d, sizeof(T_C) = %d, sizeof(T_D) = %d\n", sizeof(T_A), sizeof(T_B), sizeof(T_C), sizeof(T_D));
	
	printf("sizeof(T_E) = %d, sizeof(T_F) = %d\n", sizeof(T_E), sizeof(T_F));
	
	return 0;
}

        运行结果截图如下:

         结论:由于编译器给结构体分配大小时,分配的大小一定是该结构体内最大系统支持类型成员(该例为int类型)的整数倍。采用字节对齐方式计算分配大小。如内嵌结构体依旧采用解析(将内置结构体解析为系统支持的类型结构)的方法去计算。

类大小

        由于类的大小涉及到虚表指针的大小,虚表指针有牵扯类的继承方式,因此以下从不含继承的单类、单一继承,多重继承三个方向分析。在此之前得明白两个概念虚表指针虚函数表

        虚表指针:指向虚函数表首地址的一个指针,存在于每个基类对象的内存中,在调用构造函数构造对象时,设置虚表指针__vfptr。
        虚函数表:在编译阶段生成,编译器将类中虚函数的地址存放在虚函数表中,虚函数表存在于全局数据区.data,每个类仅有一个,供所有对象共享

不含继承的单类:

        看一下代码案例,该运行环境为Linux下的64位操作系统。代码如下:

/*******************
Author : lijd
data   : 2019-07-11
********************/
#include<iostream>   
using namespace std;
 
// 空类(实际包含构造、析构函数等)
class A
{
};

class A_1
{
	int	a;
	char	b;
	short	c;
};

class A_2
{
	int	a;
	char	b;
	short	c;
	static int d;
};

class A_3
{
	char	b;
	int	a;
	short	c;
};

int main()
{
    cout << "sizeof(A)    : " << sizeof(A) << endl;
    cout << "sizeof(A_1)  : " << sizeof(A_1) << endl;
    cout << "sizeof(A_2)  : " << sizeof(A_2) << endl;
    cout << "sizeof(A_3)  : " << sizeof(A_3) << endl;

    return 0;
}

        运行结果如下:

        空类即什么都没有的类,照理说大小应该是0,但是空类的大小为1,因为空类可以实例化,实例化必然在内存中占有一个位置,因此,编译器为其优化为一个字节大小。

        由以上运行结果分析:不含继承的单类大小跟成员函数、静态成员变量无关,跟普通成员变量有关,关系类似于上述的结构体大小计算。

含虚函数的单一继承:

        看一下代码案例,该运行环境为Linux下的64位操作系统。代码如下:

/*******************
Author : lijd
data   : 2019-07-11
********************/
#include<iostream>   
using namespace std;

class B
{
    virtual void Fun();
    char a;
};

class B_1: public B
{
    int a;
    void Fun();
    virtual void Fun1();
};



int main()
{
    cout << "sizeof(B)    : " << sizeof(B) << endl;
    cout << "sizeof(B_1)  : " << sizeof(B_1) << endl;
    return 0;
}

         运行结果如下:

        由于基类B中包含一个char类型的私有变量和一个虚函数,此时B类的内存布局如下:

        派生类B_1继承了基类B,它有自己的int类型的成员变量且重写了基类B中的虚函数Fun(),还定义了自己的虚函数。此时B_1类的内存布局如下:

含虚函数的多重继承:

        看一下代码案例,该运行环境为Linux下的64位操作系统。代码如下:

/*******************
Author : lijd
data   : 2019-07-11
********************/
#include<iostream>   
using namespace std;

class C
{
    virtual void Fun();
	virtual void Fun1();
	char a;
};

class D
{
	virtual void Fun();
	virtual void Fun2();
	int b;
};

class C_D : public C, public D
{
	void Fun();
	virtual void Fun3();
	double c;
};

int main()
{
	cout << "sizeof(C)    : " << sizeof(C) << endl;
	cout << "sizeof(D)    : " << sizeof(D) << endl;
	cout << "sizeof(C_D)  : " << sizeof(C_D) << endl;
    return 0;
}

        运行结果如下:

         由于基类C和基类D大小跟上面所述的含虚函数的单一继承类中的基类结构相同,因此不再赘述。派生类C_D继承了基类C和基类D,此时C_D类的内存布局如下:

        C_D类自己的虚函数表指针与其声明继承顺序的第一个基类C的虚函数表指针合并,此外,若C_D类重写了基类中同名的虚函数,则在对应虚函数表的对应位置都应该予以修改。C_D中新添加的虚函数位于第一个虚函数表项最后面,C_D中新添加的成员变量位于类的最后面,按其声明顺序与内存对齐原则进行排列。

总结:

        与类大小有关的因素:普通成员变量,虚函数,继承(单一继承,多重继承)

        与类大小无关的因素:静态成员变量,成员函数

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值