關於計算機中數據類型存儲的對齊問題

許多計算機系統對基本數據類型的合法地址做出了一些限制,要求某種類型對象的地址必須是某個值K(通常是2,、4、8)的倍數,這種對齊限制簡化了形成處理器和存儲器系統之間接口的硬件設計,並且提高了存取效率,雖然可能浪費了空間。所以瞭解對齊,可以使我們在不降低效率的情況下以最低的空間存儲數據

不同的硬件結構對對齊有不同的要求,IA32(Intel Architecture 32)硬件無論數據是都對齊,都能正常工作,但是,Intel還是建議要數據對齊以提高存儲器系統性能。

對Linux系統來說,2字節數據類型(如short)的地址必須是2的倍數,而較大的數據類型(int、int*、float、double)的地址必須是4的倍數。

對windows不一樣,double或者long long類型數據的地址是8的倍數。

看一下測試代碼:(win7 32bit  VC++平臺)

#include <stdio.h>

struct A {
	char c;
	int i;
	short s;
};

struct B {
	char c;
	short s;
	int i;
};

#pragma pack(1) //按1字節對齊
struct C {
	char c;
	short s;
	int i;
};
#pragma pack() //取消對齊

struct Test {
	char c;
	int i ;
	float f;
	double d;
	int *pa;
	char *pc;
	short s;
};

struct TestOptimize {
	char c;
	short s;
	int i ;
	float f;
	double d;
	int *pa;
	char *pc;	
};

#pragma pack(1)
struct Test1 {
	char c;
	int i ;
	float f;
	double d;
	int *pa;
	char *pc;
	short s;
};
#pragma pack()

int main(){

	printf("%d\n",sizeof(A));
	printf("%d\n",sizeof(B));
	printf("%d\n",sizeof(C));
	printf("%d\n",sizeof(Test));
	printf("%d\n",sizeof(TestOptimize));
	printf("%d\n",sizeof(Test1));
	return 0;
}
打印結果:

12

8

7

40

32

27


對於A,char後面補齊是爲了int能夠對齊,但是爲什麼short後面也插入兩個字節呢,因爲A可能被申明爲一個數組,如果是數組,也必須滿足每個元素地址是4的倍數對齊,因此會被補齊。結構體默認會以佔用空間最大的那個字段的字節數倍數爲地址值

並且可以看出B是對A的一種優化,調整一下字段存儲順序,就可以節省出一些空間,並且不影響存取效率

同樣的代碼,我們在linux系統下再做測試(Ubuntu 14.04.2 LTS \n \l   x86_64 x86_64 x86_64 GNU/Linux (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ))我的是ubuntu64位系統

輸出結果:

12
8
7
48
40
35
這裏Test 和TestOptimize和Test1都不一樣了。因爲64位系統指針類型是64bit即8 B。下面是在win7 32 VC6.0下Test/TestOptimize/Test1與ubuntu64 gcc4.8.2下面的對比。



總結:

1.字節對齊是和硬件相關的限制,一些硬件必須要字節對齊(從而提高訪問效率),另外一些硬件可以支持對齊或者不對齊,像IA32架構,但是建議字節對齊,這樣能夠提高存儲器效率。

2.基本數據類型存放首地址一般是該數據類型自身長度的整數倍,一般都是1、2、4、8的倍數。對於複合數據類型,像結構體,首地址需要是他成員中最長字段的整數倍。

3.另外,結構體爲了滿足結構體數組的存儲要求,可能在最後面也補0以便下一個元素的首地址也是對齊的。計算結構體所佔的內存空間有一個小技巧,就是畫位圖。通過最長字段確定位圖的寬度,然後再根據各個字段首地址對齊要求,畫出整個位圖。就像我上面的圖一樣。

4.注意,不同平臺不同編譯器最後的對齊效果也不一定相同,字段的位置具體在哪個地方也是有多種可能的。

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