C\C++ 內存對齊現象
前幾天一個在自學C語言的小伙伴問了我個問題,C語言結構體儲存所占空間為啥和自己預測的不一樣。看一下下面這一段代碼:
struct node{ int num; char ch; }a; printf("%d",sizeof(a));
在我們主動去申請內存的角度看來,申請一個上面的結構體,sizeof( int ) = 4; sizeof( char ) =1; sizeof( node ) 應該等于5才對,但是程序運行得出的卻是8。
小伙伴對于這個結果很是不解。這其實是C\C++ 儲存規則中的內存對齊(字節對齊)原則。
一 什么是字節對齊
現代計算機中,內存空間按照字節劃分,理論上可以從任何起始地址訪問任意類型的變量。但實際中在訪問特定類型變量時經常在特定的內存地址訪問,這就需要各種類型數據按照一定的規則在空間上排列,而不是順序一個接一個地存放,這就是對齊。
二 對齊的原因和作用
不同硬件平臺對存儲空間的處理上存在很大的不同。某些平臺對特定類型的數據只能從特定地址開始存取,而不允許其在內存中任意存放。例如Motorola 68000 處理器不允許16位的字存放在奇地址,否則會觸發異常,因此在這種架構下編程必須保證字節對齊。
但最常見的情況是,如果不按照平臺要求對數據存放進行對齊,會帶來存取效率上的損失。比如32位的Intel處理器通過總線訪問(包括讀和寫)內存數據。每個總線周期從偶地址開始訪問32位內存數據,內存數據以字節為單位存放。如果一個32位的數據沒有存放在4字節整除的內存地址處,那么處理器就需要2個總線周期對其進行訪問,顯然訪問效率下降很多。
因此,通過合理的內存對齊可以提高訪問效率。為使CPU能夠對數據進行快速訪問,數據的起始地址應具有“對齊”特性。比如4字節數據的起始地址應位于4字節邊界上,即起始地址能夠被4整除。
單純的文字說明還是沒那么好理解,下面我將通過幾程序來讓我們更清楚的了解到什么是內存對齊。ps: int的內存大小會隨著操作系統的位數發生變化
#include "stdio.h" struct node1 { char a;char b; }; struct node2 { short a;char b; }; struct node3 { int a;char b; };
struct node4 { long a;char b; }; struct node5 { double a;char b; }; int main() { node1 char_char; node2 short_char; node3 int_char; node4 long_char; node5 double_char; //程序輸出: printf("%d\n",sizeof(char_char)); // 2 printf("%d\n",sizeof(short_char)); // 4 printf("%d\n",sizeof(int_char)); // 8 printf("%d\n",sizeof(long_char)); // 8 printf("%d\n",sizeof(double_char)); // 16 return 0; }
從上面這段代碼及其輸出結果,我們能夠較為清晰的看到每個結構體的所占空間大小,均為其占內存較大的單位變量大小的倍數。
然后考慮到如果我們需要在一個結構體內存很多個不同單位的變量時候是怎么存的呢?
#include "stdio.h" struct node{ char ch; char ch1; short st; char ch2; int it; char ch3; double db;char ch4; }nd; int main(){ //程序輸出: printf("%d",sizeof(nd)); //32 return 0; }
這下又讓人迷惑了,雖然確實是 較大內存的double類型的整數倍 3*8 但是具體怎么儲存的呢,我們輸出一下這個結構體每個子成員的地址。
printf("&ch=0x%X &ch1=0x%X &st=0x%X &ch2=0x%X \n",&nd.ch,&nd.ch1,&nd.st,&nd.ch2); printf("&it=0x%X &ch3=0x%X &db=0x%X &ch4=0x%X \n",&nd.it,&nd.ch3,&nd.db,&nd.ch4);

這樣有點抽象,不妨畫個圖:

可以很明顯看到,圖表中的所有地址就是整個結構體占用的所有空間。 內存申請空間以double對齊。交換一下結構體的聲明順序:
struct node{ char ch; char ch1; int it; char ch3; short st; char ch2; char ch4; double db; }nd;
這下算比較清晰了,int類型以四個字節進行對齊,short類型以兩個字節進行對齊,char類型在對齊規則下進行單字節填充。
所以可以看到在定義結構體的時候進行適當的元素順序調整可以有效的節省內存空間。
包含字符串的結構體也是如此:
當然我們也可以通過 #pragma pack(n) 來改變這個內存對齊的方式:
#include "stdio.h" #pragma pack(1)//設定為 1 字節對齊 double a; struct node{ char ch; char ch1; int it; char ch3; short st; char ch2; char ch4; double db; }nd; int main(){ printf("%d\n",sizeof(nd)); printf("&ch=0x%X &ch1=0x%X &st=0x%X &ch2=0x%X \n",&nd.ch,&nd.ch1,&nd.st,&nd.ch2); printf("&it=0x%X &ch3=0x%X &db=0x%X &ch4=0x%X \n",&nd.it,&nd.ch3,&nd.db,&nd.ch4); return 0; }
內存對齊調整前


內存對齊調整后


調整內存就會出現前面文本所說處理器訪問效率變低的問題。


浙公網安備 33010602011771號