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

說明:暑假中看書想到的一點東西,因當時沒有電腦,無法驗證,所以到學校後驗證一下才發。
     
   先看一個例子,有三個結構體的定義如下:
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. 以上是我關於結構體大小的一點的一點想法,不知正確與否,歡迎批評指正。

發佈了36 篇原創文章 · 獲贊 4 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章