關於記憶體對齊
一:1.什麼是記憶體對齊
假設我們同時宣告兩個變數:
char a;
short b;
用&(取位址符號)觀察變數a,
如果a的位址是0x0000,那麼b的位址將會是0x0002或者是0x0004。
那麼就出現這樣乙個問題:0x0001這個位址沒有被使用,那它幹什麼去了?答案就是它確實沒被使用。因為cpu每次都是從以2位元組(16位cpu)或是4位元組(32位cpu)的整數倍的記憶體位址中讀進資料的。如果變數b的位址是0x0001的話,那麼cpu就需要先從0x0000中讀取乙個short,取它的高8位放入b的低8位,然後再從0x0002中讀取下乙個short,取它的低8位放入b的高8位中,這樣的話,為了獲得b的值,cpu需要進行了兩次讀操作。
但是如果b的位址為0x0002,
那麼cpu只需一次讀操作就可以獲得b的值了。所以編譯器為了優化**,往往會根據變數的大小,將其指定到合適的位置,即稱為記憶體對齊(對變數b做記憶體對齊,a、b之間的記憶體被浪費,a並未多佔記憶體)。
2.結構體內存對齊規則
結構體所占用的記憶體與其成員在結構體中的宣告順序有關,其成員的記憶體對齊規則如下:
(1)每個成員分別按自己的對齊位元組數和ppb(指定的對齊位元組數,32位機預設為4)兩個位元組數最小的那個對齊,這樣可以最小化長度。
(2)複雜型別(如結構)的預設對齊方式是它最長的成員的對齊方式,這樣在成員是複雜型別時,可以最小化長度。
(3)結構體對齊後的長度必須是成員中最大的對齊引數(ppb)的整數倍,這樣在處理陣列時可以保證每一項都邊界對齊。
(4)計算結構體的記憶體大小時,應該列出每個成員的偏移位址,則其長度=最後乙個成員的偏移位址+最後乙個成員數的長度+最後乙個成員的調整引數(考慮ppb)。
下面舉例說明上述規則:
#include#pragma pack(2) //指定ppb為2
structt;#pragma pack() //恢復原來預設ppb,32位下為4
int main(int argc,char *ar**)
printf("sizeof(struct t));
return 0;
最後輸出的結果為:8。語句#pragma pack(2)的作用是指定結構體按2位元組對齊,即ppb=2。分析如下:
變數a預設為1位元組,pb=2,所以a按1位元組對齊,a的偏移位址為0。
變數b預設為4位元組(在32位機器中int為4位元組),pb=2,所以b按2位元組對齊,b的偏移位址為2。
變數c預設為1位元組,pb=2,所以c按1位元組對齊,偏移位址為6。
此時結構體的計算出的位元組數為7個位元組。最後按規則3,結構體對齊後的位元組數為8。sizeof(t)=6+1+1=8
3.範例
(1)#pragma pack(2) //指定ppb為2
structt;
則sizeof(t)=最後乙個成員的偏移位址+最後乙個成員數的長度=2+4=6。
(2)structt1;structt2;
ppb=4,則sizeof(t1)=4+4=8;sizeof(t2)=8+1=9,9不能整除4,故調整數為3,即sizeof(t2)=8+1+3=12
4.注意的問題
(1)位元組對齊取決於編譯器;
(2)一定要注意ppb大小,ppb大小由pragam pack(n)指定;
(3)結構體占用的位元組數要能被ppb整除。
二:(1)sizeof也可以對乙個函式呼叫求值,其結果是函式返回型別的大小,函式並不會被呼叫。
(2)終於搞懂struct結構體內存分配問題了,結構體中各個成員位元組對齊遵循以下幾個原則: 直接用下面幾個原則即可判斷結構體的大小
1.結構體每個成員相對於結構體首位址的偏移量(offset)都是(這個)成員大小的整數倍,如有需要編譯器會在成員之間加上填充位元組(internaladding);
例如有以下乙個結構體
structex {inti;chart;intn;
第1個成員偏移量為0,是int型成員大小4(假設這太機器的整型長度佔4個位元組)的整數倍。
第2個成員t為char型,他的大小為1,首先假設在成員i和t之間沒有填充位元組,由於i是整型,佔4個位元組那麼在沒有填充之前,第2個成員t相對於結構體的偏移量為4,他是t成員大小1的4倍,符合此條件,所以系統在給結構體第2個成員分配記憶體時,不會在i和t之間填充位元組以到達對齊的目的。
當分配結構體第3個成員n時,首先發現是乙個整型資料,大小為4,沒有填充之前,n相對於結構體首位址偏移量為:前面2個成員+填充位元組=5,所以當系統發現5不是4(成員大小)的整數倍時,會在成員t之後(或者說n之前)填充3個位元組,以使n的偏移量到達8而成為4的整數倍。這樣這個結構體占用記憶體情況暫時為4+1+3+4。
2.結構體的總大小為結構體最寬基本型別成員大小的整數倍,如有需要編譯器會在最末乙個成員之後加上填充位元組(trailingpadding)。
上面的結構體內存分配以後還要看是否滿足此條件,假設在最末乙個成員之後不需填充位元組數,那麼這個結構體的大小為12。而ex結構體中最寬基本型別成員為int,大小為4,12為4的整數倍,所以無須再在最末乙個成員之後加上填充位元組了。所以sizeof(ex)=12;
如果乙個結構體如下所示
struc tex1{inti;chart;intn;charadd;
那麼sizeof(ex1)=16;原因就是在最後乙個成員之後填充了3個位元組。
4.對於結構體成員屬性中包含結構體變數的複合型結構體再確定最寬基本型別成員時,應當包括復合型別成員的子成員。但在確定復合型別成員的偏移位置時則是將復合型別作為整體看待。
5總結出乙個公式:結構體的大小等於最後乙個成員的偏移量加上其大小再加上末尾的填充位元組數目,即:
sizeof( struct ) = offsetof( last item ) + sizeof( last item ) +sizeof( trailing padding )
結構體的記憶體空間分配原理
關於記憶體對齊 一 1.什麼是記憶體對齊 假設我們同時宣告兩個變數 char a short b 用 取位址符號 觀察變數a,如果a的位址是0x0000,那麼b的位址將會是0x0002或者是0x0004。那麼就出現這樣乙個問題 0x0001這個位址沒有被使用,那它幹什麼去了?答案就是它確實沒被使用。...
結構體的記憶體空間分配原理
關於記憶體對齊 一 1.什麼是記憶體對齊 假設我們同時宣告兩個變數 char a short b 用 取位址符號 觀察變數a,如果a的位址是0x0000,那麼b的位址將會是0x0002或者是0x0004。因為cpu每次都是從以2位元組 16位cpu 或是4位元組 32位cpu 的整數倍的記憶體位址中...
結構體的大小 結構體對齊問題
c語言中,基本資料型別與作業系統有關 雖然直接與編譯器相關 基本沒有什麼變化。比如在32位作業系統中,int佔4個位元組,long佔4個位元組,char佔1個位元組,double佔8個位元組。但是結構體的大小並不只與作業系統有關了,與編譯器有比較大的關係。不同的編譯器有不同的對齊方式,下面以32為l...