用一道面試題題引入
struct str1
{
char a;
int b;
float c;
double d;
};
char類型占用1個字節,int型占用4個字節,short類型占用2個字節,float占4字節,double占8字節;
那么我們可能會犯一個錯誤就是直接1+4+4+8=17,認為該結構體占用17個字節。這是錯的。
百度一了下發現這是因為計算機中存在一種叫做內存對齊的機制導致了該結果的發生。
在計算機中通常會讓CPU從內存中一次讀取若干個字節的數據,而不是一次只讀取一個字節的數據,這樣的好處是提高了計算機的效率,然而壞處也顯而易見。
假設CPU要從內存中尋找一個char型的數據和一個int型的數據,如果內存不對齊,當一次讀取四個字節時,CPU找到了char型的數據后再跨越四個字節,而此時CPU的指向到了int型的中間區域,導致這個int型變量未找到,然后CPU會返回去再次尋找,直到找到該int型變量。這樣不但沒能提高效率,反而增加了CPU的負擔。因此我們通常會在第一個char型變量后邊填充一部分數據來保證每次尋址時地址都是該數據的整數倍,這樣就避免了上述“錯誤”的發生,也就是所謂的內存對齊。
於是,我通過查閱資料總結了內存對齊的以下兩個規則:
1.起始位置為該數據類型所占內存的整數倍,若不足則將不足部分填充,使其變為該數據類型所占內存的整數倍。
2.結構體所占總內存為其成員變量中所占空間最大數據類型的整數倍。
(對於32位操作系統下各數據類型的所占內存大小可以參考這篇文章:C語言數據類型與內存映射圖)
假設上題中結構體變量是從0號內存開始存儲,用一個字節存儲了字符變量a;然后需要存儲整形變量b,這時不能直接存儲,因為對於b的起始位置不滿足為它的數據類型所占內存的整數倍,所以應將接下來的1,2,3號內存填充占位,然后再用四個字節存儲b。接下來可以直接存儲float變量c,這時已經使用了1+3+4+4=12個字節內存地址。接下來存儲double類型的d時,我們知道double類型需要占8字節的內存,12不是8的倍數,無法完成內存對齊,需要補充4個字節內存占位,然后再存儲d,這樣我們就可以計算出該結構體所占內存為12+4+8=24字節。
存儲形式如下圖:
| char a |
| int b |
| b |
| b |
| b |
| float c |
| c |
| c |
| c |
| double b |
| b |
| b |
| b |
| b |
| b |
| b |
| b |
