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類型)的整數倍。採用字節對齊方式計算分配大小。如內嵌結構體依舊採用解析(將內置結構體解析爲系統支持的類型結構)的方法去計算。

類大小

由於類的大小涉及到虛指針的大小,虛指針有牽扯類的繼承方式,因此以下從不含繼承的單類、單一繼承,多重繼承三個方向分析。

不含繼承的單類:

看一下代碼案例,該運行環境爲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中新添加的成員變量位於類的最後面,按其聲明順序與內存對齊原則進行排列。

總結:

與類大小有關的因素:普通成員變量,虛函數,繼承(單一繼承,多重繼承)

與類大小無關的因素:靜態成員變量,成員函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章