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