標籤:iostream number pac 類型 space struct nbsp 結構體 def
在用sizeof運算子求算某結構體所佔空間時,並不是簡單地將結構體中所有元素各自占的空間相加,這裡涉及到記憶體位元組對齊的問題。從理論上講,對於任何 變數的訪問都可以從任何地址開始訪問,但是事實上不是如此,實際上訪問特定類型的變數只能在特定的地址訪問,這就需要各個變數在空間上按一定的規則排列, 而不是簡單地順序排列,這就是記憶體對齊。
記憶體對齊的原因:
1)某些平台只能在特定的地址處訪問特定類型的資料;
2)提高存取資料的速度。比如有的平台每次都是從偶地址處讀取資料,對於一個int型的變數,若從偶地址單元處存放,則只需一個讀取周期即可讀取該變數;但是若從奇地址單元處存放,則需要2個讀取周期讀取該變數。
win32平台下的微軟C編譯器對齊策略:
1)結構體變數的首地址能夠被其最寬資料類型成員的大小整除。編譯器在為結構體變數開闢空間時,首先找到結構體中最寬的資料類型,然後尋找記憶體位址能被該資料類型大小整除的位置,這個位置作為結構體變數的首地址。而將最寬資料類型的大小作為對齊標準。
2)結構體每個成員相對結構體首地址的位移量(offset)都是每個成員本身大小的整數倍,如有需要會在成員之間填充位元組。編譯器在為結構體成員開闢空 間時,首先檢查預開闢空間的地址相對於結構體首地址的位移量是否為該成員大小的整數倍,若是,則存放該成員;若不是,則填充若干位元組,以達到整數倍的要 求。
3)結構體變數所佔空間的大小必定是最寬資料類型大小的整數倍。如有需要會在最後一個成員末尾填充若干位元組使得所佔空間大小是最寬資料類型大小的整數倍。
下面看一下sizeof在計算結構體大小的時候具體是怎樣計算的
test 空結構體
則sizeof(S)=1;或sizeof(S)=0;
在C++中佔1位元組,而在C中佔0位元組。
1.test1
typedef struct node1{ int a; char b; short c;}S1; |
則sizeof(S1)=8。這是因為結構體node1中最長的資料類型是int,佔4個位元組,因此以4位元組對齊,則該結構體在記憶體中存放方式為
|--------int--------| 4位元組
|char|----|--short-| 4位元組
總共佔8位元組
2.test2
typedef struct node2{ char a; int b; short c;}S2; |
則siezof(S3)=12.最長資料類型為int,佔4個位元組。因此以4位元組對齊,其在記憶體空間存放方式如下:
|char|----|----|----| 4位元組
|--------int--------| 4位元組
|--short--|----|----| 4位元組
總共佔12個位元組
3.test3 含有待用資料成員
typedef struct node3{ int a; short b; static int c;}S3; |
則sizeof(S3)=8.這裡結構體中包含待用資料成員,而待用資料成員的存放位置與結構體執行個體的儲存地址無關(注意只有在C++中結構體中才能含有待用資料成員,而C中結構體中是不允許含有待用資料成員的)。其在記憶體中儲存方式如下:
|--------int--------| 4位元組
|--short-|----|----| 4位元組
而變數c是單獨存放在待用資料區的,因此用siezof計算其大小時沒有將c所佔的空間計算進來。
4.test4 結構體中含有結構體
typedef struct node4{ bool a; S1 s1; short b;}S4; |
則sizeof(S4)=16。是因為s1佔8位元組,而s1中最長資料類型為int,佔4個位元組,bool類型1個位元組,short佔2位元組,因此以4位元組對齊,則儲存方式為
|-------bool--------| 4位元組
|-------s1----------| 8位元組
|-------short-------| 4位元組
5.test5
typedef struct node5{ bool a; S1 s1; double b; int c;}S5; |
則sizeof(S5)=32。是因為s1佔8位元組,而s1中最長資料類型為int,佔4位元組,而double佔8位元組,因此以8位元組對齊,則存放方式為:
|--------bool--------| 8位元組
|---------s1---------| 8位元組
|--------double------| 8位元組
|----int----|---------| 8位元組
6.test6
若在程式中使用了#pragma pack(n)命令強制以n位元組對齊時,預設情況下n為8.
則比較n和結構體中最長資料類型所佔的位元組大小,取兩者中小的一個作為對齊標準。
若需取消強制對齊,則可用命令#pragma pack()
如果在程式開頭使用命令#pragma pack(4),對於下面的結構體
typedef struct node5{ bool a; S1 s1; double b; int c;}S5; |
則sizeof(S5)=24.因為強制以4位元組對齊,而S5中最長資料類型為double,佔8位元組,因此以4位元組對齊。在記憶體中存放方式為:
|-----------a--------| 4位元組
|--------s1----------| 4位元組
|--------s1----------| 4位元組
|--------b-----------| 4位元組
|--------b-----------| 4位元組
|---------c----------| 4位元組
總結一下,在計算sizeof時主要注意一下幾點:
1)若為空白結構體,則只佔1個位元組的單元
2)若結構體中所有資料類型都相同,則其所佔空間為 成員資料類型長度×成員個數
若結構體中資料類型不同,則取最長資料類型成員所佔的空間為對齊標準,資料成員包含另一個結構體變數t的話,則取t中最 長資料類型與其他資料成員比較,取最長的作為對齊標準,但是t存放時看做一個單位存放,只需看其他成員即可。
3)若使用了#pragma pack(n)命令強制對齊標準,則取n和結構體中最長資料類型占的位元組數兩者之中的小者作為對齊標準。
另外除了結構體中存在對齊之外,普通的變數儲存也存在位元組對齊的情況,即自身對齊。編譯器規定:普通變數的儲存首地址必須能被該變數的資料類型寬度整除。
/*測試sizeof運算子 2017.10.25*/ #include <iostream>using namespace std;//#pragma pack(4) //設定4位元組對齊//#pragma pack() //取消4位元組對齊 typedef struct node{ }S; typedef struct node1{ int a; char b; short c;}S1; typedef struct node2{ char a; int b; short c;}S2; typedef struct node3{ int a; short b; static int c;}S3; typedef struct node4{ bool a; S1 s1; short b;}S4; typedef struct node5{ bool a; S1 s1; double b; int c;}S5;
int main(int argc, char *argv[]){ cout <<sizeof(char)<<" "<<sizeof(short)<<" "<<sizeof(int)<<" "<<sizeof(float)<<" "<<sizeof(double)<<endl; S s; S1 s1; S2 s2; S3 s3; S4 s4; S5 s5; cout<<sizeof(S3)<<endl; cout<<sizeof(s)<<" "<<sizeof(s1)<<" "<<sizeof(s2)<<" "<<sizeof(s3)<<" "<<sizeof(s4)<<" "<<sizeof(s5)<<endl; return 0;}
C/C++ 結構體位元組對齊