現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。
(1)現象
比如有些平台每次讀都是從偶位址開始,如果乙個int型(假設為32位系統)如果存放在偶位址開始的地方,那麼乙個讀週期就可以讀出這32bit,而如果存放在奇位址開始的地方,就需要2個讀週期,並對兩次讀出的結果的高低位元組進行拼湊才能得到該32bit資料。顯然在讀取效率上下降很多。看下面乙個例子:
32位機上,預設4位元組對齊
struct a
int a;
char b;
short c;
struct b
char b;
int a;
short c;
main()
struct a x;
struct b y;
printf("%d %d", sizeof(x),sizeof(y));
得到的結果是8,12。按理說兩者應該一樣是7才對?之所以出現上面的結果是因為編譯器要對資料成員在空間上進行對齊。對a,a佔4位元組,b佔一位元組,c佔兩位元組,b、c可以放在乙個4位元組裡面,且最小分配是4,所以共佔8;對b,b佔一位元組,但它容納不了a了,所以a要佔另外4位元組,b只能單佔4位元組,後面的c也只能單佔4位元組,也即沒有共用的,所以佔12。可見次序是有影響的。
上面是按照編譯器的預設設定進行對齊的結果,那麼我們是不是可以改變編譯器的這種預設對齊設定呢?當然可以。
#pragma pack(2)
struct b
;int _tmain()
輸出是8,因為是2位元組對齊最小可以2位元組分配,b佔兩位元組,a佔4位元組,c佔2位元組。類似的還有如下:
#pragma pack(1)
struct b
;int _tmain()
輸出是7,因為1位元組對齊,最小可以分配1。那麼b佔一位元組,a佔4位元組,c佔2位元組。
(2)原則歸納
綜合如下,對齊的原則:
1,資料型別自身的對齊值:對於char型資料,其自身對齊值為1,對於short型為2,對於int,float,double型別,其自身對齊值為4,單位位元組。
2,結構體或者類的自身對齊值:其成員中自身對齊值最大的那個值。
3,指定對齊值:#pragma pack (value)時的指定對齊值value。
(3)如何使用
如何修改編譯器的預設對齊值?
1,在vc ide中,可以這樣修改:[project]|[settings],c/c++選項卡category的code generation選項的struct member alignment中修改,預設是8位元組。
2,在編碼時,可以這樣動態修改:#pragma pack 。
3,如果在程式設計的時候要考慮節約空間的話,那麼我們只需要假定結構的首位址是0,然後各個變數按照上面的原則進行排列即可。基本的原則就是把結構中的變數按照型別大小從小到大宣告,儘量減少中間的填補空間。還有一種就是為了以空間換取時間的效率,比如:有一種使用空間換時間做法是顯式的插入reserved成員:
struct a
reserved成員對我們的程式沒有什麼意義,它只是起到填補空間以達到位元組對齊的目的,當然即使不加這個成員通常編譯器也會給我們自動填補對齊,我們自己加上它只是起到顯式的提醒作用。
關於結構體的成員對齊與結構體整體對齊
大多數計算機體系結構中,對記憶體操作時按整字訪問才能達到最高效率,相當於是以空間換取時間,看似浪費了記憶體空間,但換來了訪問效率,先來說說三個概念 系統對齊值,自身對齊值,有效對齊值,三個概念的單位均為位元組,一開始概念不懂沒關係,可以對照後面的程式和記憶體分布圖來理解 1,系統對齊值 對於不同的作...
結構體中的成員對齊
關於結構體中成員對齊的總結 a.結構體中,結構體成員要對齊到其對齊值倍數的位址上,對齊值為min 成員型別對齊值,編譯器結構成員對齊值b.結構體本身的對齊值為其所有成員中最大的對齊值。c.結構體本身要對齊到其對齊值倍數的位址上。d.結構體中的結構體要對齊到其對齊值倍數的位址上。e.結構體成員在記憶體...
結構體成員的記憶體對齊
include void printf arr quint8 data,int len,quint8 base num if 16 base num printf n struct frame big struct frame small struct frame union union int m...