天天看點

結構體元素順序與結構體的大小

說明:暑假中看書想到的一點東西,因當時沒有電腦,無法驗證,是以到學校後驗證一下才發。

   先看一個例子,有三個結構體的定義如下:

struct  a    

{

 bool    b1;

 bool    b2;

 int     i1;

 int     i2;

 int     i3;

};

struct  b

{

 int     i1;

 int     i2;

 int     i3;

 bool    b1;

 bool    b2;

};

struct  c

{

 int       ii1;

 bool      bb1;

 int       ii2;

 bool      bb2;

 int       ii3;

};

   對于上面定義的兩個結構體,考慮下面的兩個問題:

   1.三個結構體大小的理論值和實際值各是多少?

   2.三個結構體所占的記憶體空間大小(實際所占非理論值)是否相同?為什麼?

對于1我們很容易得出結果,三個結構體大小的理論值都是14。因為在32位的系統中int的大小是4byte,bool的大小為1byte,而結構體的大小為各元素所占大小的和,是以理論值為14,至于實際大小我們也可以很容易的得到:

#include<iostream>

using namespace std;

int main()

{

 cout<<"a's size:/t"<<sizeof(a)<<endl;

        cout<<"b's size:/t"<<sizeof(b)<<endl;

        cout<<"c's size:/t"<<sizeof(c)<<endl;

        return 0;

}

可以得到大小依次是:16,16,20,這樣第一個問題就解決了,第二個問題也解決了一部分。至于問什麼這樣呢,這與微機系統的記憶體組織有關。

    在微機系統中,存儲器是分體的,具體的說16位的系統分為2個存儲體,32位的系統分為4存儲體。因為存儲器是分體的,在存儲資料時應考慮資料存儲的位置盡量以偶位址(16位)或4的倍數(32位)開始,也就是所謂的“對準”。如果在16位的系統中存放一個字(2byte)的資料時,如果以奇位址開始,那麼在讀一個字的時候就需要2個時鐘周期,而以偶位址開始存儲是指需要一個時鐘周期。是以所謂的對準也就是用空間換取時間的一種方法。我們可以猜測在32位的編譯器中,便量存放的位址應該是以4的位址的倍數開始的,這是可以驗證的:

#include<iostream>

using namespace std;

#include<iostream>

using namespace std;

int main()

{

 int a;

 bool b1,b2;

 float c;

 double d;

 cout<<"variable/t"<<"Address"<<endl;

 cout<<"a/t/t"<<&a<<endl;

 cout<<"b1/t/t"<<&b1<<endl;

 cout<<"b2/t/t"<<&b2<<endl;

 cout<<"c/t/t"<<&c<<endl;

 cout<<"d/t/t"<<&d<<endl;

 return 0;

}

輸出結果如下:

variable        Address

a               0012FF7C

b1              0012FF78

b2              0012FF74

c               0012FF70

d               0012FF68

下面看一下上面定義的結構體的各成員的位址配置設定:

int  main()

{

 a  aa;

 b  bb;

 c  cc;

 cout<<"int size:/t"<<sizeof(int)<<"byte"<<endl;

 cout<<"bool size:/t"<<sizeof(bool)<<"byte"<<endl;

 cout<<"size  a :"<<sizeof(a)<<endl;

 cout<<"Address of element in aa:"<<endl;

 cout<<"b1's  address/t/t"<<&(aa.b1)<<endl;

 cout<<"b2's  address/t/t"<<&(aa.b2)<<endl;

 cout<<"i1's  address/t/t"<<&(aa.i1)<<endl;

 cout<<"i2's  address/t/t"<<&(aa.i2)<<endl;

 cout<<"i3's  address/t/t"<<&(aa.i3)<<endl;

 cout<<"size  b :"<<sizeof(b)<<endl;

 cout<<"Address of element in bb:"<<endl;

 cout<<"i1's  address/t/t"<<&(bb.i1)<<endl;

 cout<<"i2's  address/t/t"<<&(bb.i2)<<endl;

 cout<<"i3's  address/t/t"<<&(bb.i3)<<endl;

 cout<<"b1's  address/t/t"<<&(bb.b1)<<endl;

 cout<<"b2's  address/t/t"<<&(bb.b2)<<endl;

 cout<<"size b:"<<sizeof(c)<<endl;

 cout<<"Address of element in cc:"<<endl;    

 cout<<"i1's  address/t/t"<<&(cc.i1)<<endl;

 cout<<"b1's  address/t/t"<<&(cc.b1)<<endl;

 cout<<"i2's  address/t/t"<<&(cc.i2)<<endl;

 cout<<"b2's  address/t/t"<<&(cc.b2)<<endl;

 cout<<"i3's  address/t/t"<<&(cc.i3)<<endl;

 return 0;

}

運作結果:

int size:       4byte

bool size:      1byte

size  a :16

Address of element in aa:

b1's  address           0012FF70

b2's  address           0012FF71

i1's  address           0012FF74

i2's  address           0012FF78

i3's  address           0012FF7C

size  b :16

Address of element in bb:

i1's  address           0012FF60

i2's  address           0012FF64

i3's  address           0012FF68

b1's  address           0012FF6C

b2's  address           0012FF6D

size b:20

Address of element in cc:

i1's  address           0012FF4C

b1's  address           0012FF50

i2's  address           0012FF54

b2's  address           0012FF58

i3's  address           0012FF5C

通過結果就可以說明為什麼結構體的大小因元素的位置不一樣而大小不一樣了。因為編譯器在存儲是采用了對齊(對準),是以大小有所不同。結構體a中兩個布爾變量b2的位址并不是4的倍數,這并不沖突,因為在這裡把結構體看作是像内部類型一樣的類型,其内部元素對外是作為一個整體的。

    是以,在聲明一個結構體時,盡量按一頂的順序(從大到小或從小到大)來排列各元素,這樣就可以減少其所占的空間,不過現在記憶體空間已不再是着重考慮的問題,因為也可以從便于閱讀的方面去排列。

  PS. 以上是我關于結構體大小的一點的一點想法,不知正确與否,歡迎批評指正。

上一篇: const 用法