結構體字節對齊

在嵌入式開發時,常常需要注意結構體的字節對齊。當然了,不是說在PC上開發程序時不需要關注。只是兩者關注的程度不一樣。同時,不同的操作系統或者操作需求,字節對齊的原則也不一樣。下面針對在PC上Microsoft Visual Stdio上分析結構體字節對齊的問題。

在使用sizeof運算符計算結構體佔用的內存大小時,不是簡單的將成員變量所佔用的內存大小直接相加。這中間涉及到內存字節對齊的問題。爲什麼會存在字節對齊的問題呢?這是操作系統對內存操作、CPU機器週期等的優化的產物。如有的平臺在地址爲偶數的地方存取數據,而有的平臺在奇數地址存取數據。如果在偶數地址存取數據的平臺上,訪問奇數地址的內容,則多需要一個讀取指令。同樣的問題會存在奇數地址存取的平臺。爲此有了內存對齊的概念。

以下在win32平臺上討論字節對齊的問題,其對齊策略有:

1)結構體變量的首地址能夠被其最寬數據類型成員的大小整除。編譯器在爲結構體變量開闢空間時,首先找到結構體中最寬的數據類型,然後尋找內存地址能被該數據類型大小整除的位置,這個位置作爲結構體變量的首地址。而將最寬數據類型的大小作爲對齊標準。

struct 
{
	char a;
	short b;
	char c;
}stc_one;
&stc_one 0x00428278
&stc_one.a 0x00428278
&stc_one.b 0x0042827a
&stc_one.c 0x0042827c

可以看出這個結構體中最寬的數據類是short,佔用2個字節。結構體變量的首地址可以被2整除。這個結構體是以2個字節爲標準進行對齊的。

2)結構體每個成員相對結構體首地址的偏移量(offset)都是每個成員本身大小的整數倍,如有需要會在成員之間填充字節。編譯器在爲結構體成員開闢空 間時,首先檢查預開闢空間的地址相對於結構體首地址的偏移量是否爲該成員大小的整數倍,若是,則存放該成員;若不是,則填充若干字節,以達到整數倍的要 求。

3)結構體變量所佔空間的大小必定是最寬數據類型大小的整數倍。如有需要會在最後一個成員末尾填充若干字節使得所佔空間大小是最寬數據類型大小的整數倍

struct 
{
	char a;
	short b;
	char c;
	long d;
}stc_one;
該結構體中的最寬數據類型是long,其佔用內存空間大小爲4個字節,sizeof(stc_one) = 12.

下面結合實例一起看下sizeof是如何計算結構體佔用的內存打下的。

1、空結構體:

struct 
{

}stc_three;
在C++的編譯中爲1個字節,而在C編譯器中爲0字節。

2、

struct 
{
	char a;
	int	 b;
	short c;
}stc_four;
該結構體以int型爲標準,即以4字節爲標準進行內存對齊。所以sizeof(stc_four) = 12個字節。

3、含有靜態數據成員(注意:在C語言中的結構體中,是不允許有靜態成員的。只有在C++中纔可以)

struct 
{
	int a;
	long b;
	static long c;
}stc_five;
成員變量c是存放在靜態區,沒有在stc_five變量的存儲空間中,所以sizeof(stc_five) = 8個字節。

4、結構體中包含結構體

typedef struct 
{
	char a;
	short b;
	char c;
	//long d;
}stc_one;
struct 
{
	bool   a;
	stc_one b;
	int c;	
}stc_six;
在stc_six中最寬的變量長度是stc_one,其爲6個字節,所以在這6個字節中找最寬的變量長度作爲stc_six的內存對齊標準。所以是2字節爲標準對stc_six進行內存對齊的。故sizeof(stc_six) = 12個字節。注意:不要將stc_one完全拆開來比較。

在此,需要將stc_one和stc_six中的最寬成員變量進行比較,選擇大的作爲內存對齊的標準。即,如果stc_one大於stc_six中的其他成員變量的空間時,選用stc_one中的最寬成員變量的佔用內存大小最爲標準進行內存對齊。如果stc_one小於stc_six中的其他成員變量的空間時,選用佔用空間大的作爲標準。

5、強制以某一個數值爲標準進行內存對齊

若在程序中使用了#pragma pack(n)命令強制以n字節對齊時,默認情況下n爲8.

則比較n和結構體中最長數據類型所佔的字節大小,取兩者中小的一個作爲對齊標準。

若需取消強制對齊方式,則可用命令#pragma pack()

#pragma pack(1)

typedef struct 
{
	char a;
	short b;
	char c;
	//long d;
}stc_one;

#pragma pack()

那麼sizeof(stc_one) = 4個字節。








發佈了6 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章