struct結構體佔內存大小計算

注意:struct 的{}後面要加上 ”;“

#include<stdio.h>
struct A
{
           int a;
          double b;
           char c;
};
struct B
{
           double b;
            char c;
            int a;
};
struct C
{
            int a;
            char c;
            double b;
};
int main(void)
{
          A aa;
          B bb;
          C cc;
          printf("A = %d\n", sizeof(aa));//結果:A = 24
          printf("B = %d\n", sizeof(bb));//結果:B = 16
          printf("C = %d\n", sizeof(cc));//結果:C = 16
          return 0;
}
int類型一般是佔用四個字節,char類型一般佔用一個字節,double類型一般佔用8個字節。
1、結構體A首先給int a 分配四個字節,並且以4個字節對齊;然後給double b分配8個字節,發現以4個字節對齊不行,就以8個字節對齊,前面只有int a ,所以int a將佔用8個字節;最後爲了對齊,將給char c 也分配8給字節,所以結構體A佔用了24個字節。
2、結構體B首先給double 分配8個字節,並且以8給字節對齊;然後給char c分配8給字節;最後給int a分配空間的時候發現,前面空有7個字節空間可以放下int a,int a 就和char c一起佔用8個字節,所以結構體B佔用了16個字節

而在GNU GCC編譯器中,遵循的準則有些區別,對齊模數不是像上面所述的那樣,根據最寬的基本數據類型來定。在GCC中,對齊模數的準則是:對齊模數最大隻能是4,也就是說,即使結構體中有double類型,對齊模數還是4,所以對齊模數只能是1,2,4。而且在上述的三條中,第2條裏,offset必須是成員大小的整數倍,如果這個成員大小小於等於4則按照上述準則進行,但是如果大於4了,則結構體每個成員相對於結構體首地址的偏移量(offset)只能按照是4的整數倍來進行判斷是否添加填充。
看如下例子:

struct T
{
  char ch;
  double   d   ;
};
那麼在GCC下,sizeof(T)應該等於12個字節。

 

struct結構體的大小計算:
struct 大小,與pack的大小(在程序中顯示設置#pragma pack(),vc6.0默認大小爲8)、結構中最大佔用有關

struct A
{

 int a;     0-3

               4-7     要填充(padding)以保證內存對齊的原則
 double b; 8-15
 char c[9]; 16-24
};

首先給a分配內存,因爲int佔四個字節<pack大小(8個字節),所以按照4個字節對齊,起始位值爲0,0%4=0,a最後佔的內存爲0-3;

接着給b分配內存,double佔8個字節,所以按照8個字節對齊,起始位爲8(8%8=0),b爲8-15;

最後char佔一個字節,所以c爲16-24;

因此結構體A的大小爲8+8+9 = 25;有因爲25不是結構體中最大佔用內存類型double類型大小(8)的整數倍,所以A最後的大小是32;

struct B

{
int a;   

double b;     
double c;    
char d;   

};

同理,按上面的分析方法確定各個變量在內存中的位置:
a,0-3;

  ,4-7;
b,8-15;
c,16-23;
d,24;

TOTAL = 25

25 不是8的倍數,所以最後B大小是32;

總結計算結構體的步驟

1.內存對齊與編譯器設置有關,首先要搞清編譯器這個默認值是多少

2.如果不想編譯器默認的話,可以通過#pragma pack(n)來指定按照n對齊

3.每個結構體變量對齊,如果對齊參數n,變量所佔字節數(m),內存地址的起始位置%min(n,m)=0。也就是最小化長度規則

4.結構體總大小: 對齊後的長度必須是成員中最大的對齊參數的整數倍。

5.補充:如果結構體A中還要結構體B,那麼B的對齊方式是選它裏面最長的成員的對齊方式

所以計算結構體大小要走三步,首先確定是當前程序按照幾對齊(參照1,2點),接着計算每個結構體變量的大小和偏移(參照3,5),最後計算結構體總大小(參照4)。

 

如果結構體中含有位域(bit-field),那麼VC中準則又要有所更改:
1) 如果相鄰位域字段的類型相同,且其位寬之和小於類型的sizeof大小,則後面的字段將緊鄰前一個字段存儲,直到不能容納爲止;
2) 如果相鄰位域字段的類型相同,但其位寬之和大於類型的sizeof大小,則後面的字段將從新的存儲單元開始,其偏移量爲其類型大小的整數倍;
3) 如果相鄰的位域字段的類型不同,則各編譯器的具體實現有差異,VC6採取不壓縮方式(不同位域字段存放在不同的位域類型字節中),Dev-C++和GCC都採取壓縮方式;
備註:當兩字段類型不一樣的時候,對於不壓縮方式,例如:


struct N
{
  char c:2;
  int    i:4;
};

依然要滿足不含位域結構體內存對齊準則第2條,i成員相對於結構體首地址的偏移應該是4的整數倍,所以c成員後要填充3個字節,然後再開闢4個字節的空間作爲int型,其中4位用來存放i,所以上面結構體在VC中所佔空間爲8個字節;而對於採用壓縮方式的編譯器來說,遵循不含位域結構體內存對齊準則第2條,不同的是,如果填充的3個字節能容納後面成員的位,則壓縮到填充字節中,不能容納,則要單獨開闢空間,所以上面結構體N在GCC或者Dev-C++中所佔空間應該是4個字節。

4) 如果位域字段之間穿插着非位域字段,則不進行壓縮;
備註:
結構體


typedef struct
{
   char c:2;
   double i;
   int c2:4;
}N3;

在GCC下佔據的空間爲16字節,在VC下佔據的空間應該是24個字節。
5) 整個結構體的總大小爲最寬基本類型成員大小的整數倍。

ps:


對齊模數的選擇只能是根據基本數據類型,所以對於結構體中嵌套結構體,只能考慮其拆分的基本數據類型。而對於對齊準則中的第2條,確是要將整個結構體看成是一個成員,成員大小按照該結構體根據對齊準則判斷所得的大小。 
類對象在內存中存放的方式和結構體類似,這裏就不再說明。需要指出的是,類對象的大小隻是包括類中非靜態成員變量所佔的空間,如果有虛函數,那麼再另外增加一個指針所佔的空間即可。 


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/lidoublewen/archive/2009/08/21/4468264.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章