【C】C語言記憶體位元組對齊
圖:a-1
圖:a-2
記憶體對齊是會浪費一些空間的。但是這種空間上得浪費卻可以減少取數的時間。這是典型的一種以空間換時間的做法。空間與時間孰優孰略這個每個人都有自己的看法,但是C語言既然採取了這種以空間換時間的策略,就必然有它的道理。況且,在儲存器越來越便宜的今天,這一點點的空間上的浪費就不算什麼了。
需要說明的是,位元組對齊不同的編譯器可能會採用不同的優化策略,以下以GCC為例講解結構體的對齊.
一、原則:
1.結構體內成員按自身按自身長度自對齊
自身長度,如char=1,short=2,int=4,double=8,。所謂自對齊,指的是該成員的起始位置的記憶體地址必須是它自身長度的整數倍。
2.結構體的總大小為結構體的有效對齊值的整數倍
結構體的有效對齊值的確定:
1)當未明確指定時,以結構體中最長的成員的長度為其有效值
2)當用#pragma pack(n)指定時,以n和結構體中最長的成員的長度中較小者為其值。
3)當用__attribute__ ((__packed__))指定長度時,強制按照此值為結構體的有效對齊值
二、例子
1。
struct AA{
char a;
int b;
char c;
}aa;
結果,sizeof(aa)=12
何解?首先假設結構體記憶體起始地址為0,那麼地址的分佈如下
0 a
1
2
3
4 b
5 b
6 b
7 b
8 c
9
10
11
char的字對齊長度為1,所以可以在任何地址開始,但是,int自對齊長度為4,必須以4的倍數地址開始。所以,儘管1-3空著,但b也只能從4開始。再加上c後,整個結構體的總長度為9,結構體的有效對齊值為其中最大的成員即int的長度4,所以,結構體的大小向上擴充套件到12,即9-11的地址空著。
2.
struct AA{
char a;
char c;
int b;
}aa;
sizeof(aa)=8,為什麼呢
0 a
1 c
2
3
4 b
5 b
6 b
7 b
因為c為char型別,字對齊長度為1,所以可以有效的利用1-3間的空格。看見了吧,變數定義的位置的不同時有可能影響結構體的大小的哦!
3.
#pragma pack(2)
struct AA{
char a;
int b;
char c;
}aa;
sizeof(aa)=10,為什麼呢?a到c只佔9位元組長度,因為結構體的有效對齊長度在pack指定的2和int的4中取
較小的值2。故取2的倍數10。
如果當pack指定為8呢?那就仍然按4來對齊,結果仍然是12。
4.
struct AA{
char a;
int b;
char c;
}__attribute__((__8__))aa;
sizeof(aa)=16
為咩?其實a到c仍然只佔9位元組長度,但結構體以8對齊,故取8的倍數16.
如果其指定2,則結果為10
如果pragma pack和__attribute__
同時指定呢?以__attribute__ 的為準。
需要說明的是,不管pragma
pack和__attribute__如何指定,結構體內部成員的自對齊仍然按照其自身的對齊值。
另外,不同的編譯器可能會對記憶體的分佈進行優化,
例如有些編譯器會把例題1中的程式優化成例題2的樣子。但這屬於編譯器的問題,
這裡不做詳細討論。如果要作為程式設計的參考的話,最好當做編譯器不會做優化,
儘量在保持程式碼清晰的情況下,自己手動將例題1優化成例題2的樣子。
如果是做題的話,按照以上原則做就可以了,不用考慮不同編譯器的特性。struct Inventory
{
char description[15] ; //貨物名稱
char no[10] ; //貨號
int quantity ; //庫存數量
double cost ; //成本
double retail ; //零售價格
}; //sizeof:48
struct Employee
{
char name[27] ; //員工姓名
char address[30] ; //家庭住址
long int zip ; //郵政編碼 long long
long int telenum ; //聯絡電話
double salary ; //工資
}; //80
struct Mail
{
char address[30] ; //地址
long int zip ; //郵政編碼
long int telenum ; //電話號碼
}; //40
struct Employee2
{
char name[25] ; //員工姓名
Mail addinfo ; //結構作為成員,巢狀
double salary ; //工資
}; //80