結構體(struct)的sizeof值,並不是簡單的將其中各元素所佔位元組相加,而是要考慮到儲存空間的位元組對齊問題。先看下面定義的兩個結構體.
struct
{
char a;
short b;
char c;
}S1;
char b;
short c;
}S2;
分別用程式測試得出sizeof(S1)=6 , sizeof(S2)=4
可見,雖然兩個結構體所含的元素相同,但因為其中存放的元素型別順序不一樣,所佔位元組也出現差異。這就是位元組對齊原因。透過位元組對齊,有助於加快計算機的取數速度,否則就得多花指令週期。
位元組對齊原則
結構體預設的位元組對齊一般滿足三個準則:
1) 結構體變數的首地址能夠被其最寬基本型別成員的大小所整除;
2) 結構體每個成員相對於結構體首地址的偏移量(offset,即每個成員的起始地址)都是成員自身大小的整數倍,如有需要編譯器會在成員之間加上填充位元組(internal adding);
3) 結構體的總大小為結構體最寬基本型別成員大小的整數倍,如有需要編譯器會在最末一個成員之後加上填充位元組(trailing padding)。
注意:當結構體成員裡面有陣列成員時,如int a[10],要看成10個整形變數才參與計算。
透過這三個原則,就不難理解上面兩個struct的差異了.
對於struct S1, 為了使short變數滿足位元組對其準則(2), 即其儲存位置相對於結構體首地址的offset是自身大小(short佔2個位元組)的整數倍,必須在位元組a後面填充一個位元組以對齊;再由準則(3),為了 滿足結構體總大小為short大小的整數倍,必須再在c後面填充一個位元組。
對於struct S2, 卻不必如上所述的填充位元組,因為其直接順序儲存已經滿足了對齊準則。
如果將上面兩個結構體中的short都改為int(佔4個位元組), 那麼會怎麼樣呢? 程式得出sizeof(S1)=12, sizeof(S2)=8
利用上面的準則,也不難計算得出這樣的結果。S1中在a後面填充3個位元組、在c後面填充3個位元組,這樣一共12個位元組;S2中在a、b順序儲存之後填充兩個位元組用以對其,這樣一共就8個位元組。
當然,在某些時候也可以設定位元組對齊方式。這就需要使用 #pragma pack 。
#pragma pack(push) //壓棧儲存
#pragma pack(1)// 設定1位元組對齊
#pragma pack(pop) // 恢復先前設定
如上所示,將對其方式設為1位元組對齊,那麼S1就不填充位元組,sizeof為各元素所佔位元組之和即4。這一點在從外部2進位制檔案中讀入struct大小的資料到struct中,是很有用的.
另外,還有如下的一種方式:
· __attribute((aligned (n))),讓所作用的結構成員對齊在n位元組自然邊界上。如果結構中有成員的長度大於n,則按照最大成員的長度來對齊。
· __attribute__ ((packed)),取消結構在編譯過程中的最佳化對齊,按照實際佔用位元組數進行對齊。
結構體(struct)的sizeof值,並不是簡單的將其中各元素所佔位元組相加,而是要考慮到儲存空間的位元組對齊問題。先看下面定義的兩個結構體.
struct
{
char a;
short b;
char c;
}S1;
struct
{
char a;
char b;
short c;
}S2;
分別用程式測試得出sizeof(S1)=6 , sizeof(S2)=4
可見,雖然兩個結構體所含的元素相同,但因為其中存放的元素型別順序不一樣,所佔位元組也出現差異。這就是位元組對齊原因。透過位元組對齊,有助於加快計算機的取數速度,否則就得多花指令週期。
位元組對齊原則
結構體預設的位元組對齊一般滿足三個準則:
1) 結構體變數的首地址能夠被其最寬基本型別成員的大小所整除;
2) 結構體每個成員相對於結構體首地址的偏移量(offset,即每個成員的起始地址)都是成員自身大小的整數倍,如有需要編譯器會在成員之間加上填充位元組(internal adding);
3) 結構體的總大小為結構體最寬基本型別成員大小的整數倍,如有需要編譯器會在最末一個成員之後加上填充位元組(trailing padding)。
注意:當結構體成員裡面有陣列成員時,如int a[10],要看成10個整形變數才參與計算。
透過這三個原則,就不難理解上面兩個struct的差異了.
對於struct S1, 為了使short變數滿足位元組對其準則(2), 即其儲存位置相對於結構體首地址的offset是自身大小(short佔2個位元組)的整數倍,必須在位元組a後面填充一個位元組以對齊;再由準則(3),為了 滿足結構體總大小為short大小的整數倍,必須再在c後面填充一個位元組。
對於struct S2, 卻不必如上所述的填充位元組,因為其直接順序儲存已經滿足了對齊準則。
如果將上面兩個結構體中的short都改為int(佔4個位元組), 那麼會怎麼樣呢? 程式得出sizeof(S1)=12, sizeof(S2)=8
利用上面的準則,也不難計算得出這樣的結果。S1中在a後面填充3個位元組、在c後面填充3個位元組,這樣一共12個位元組;S2中在a、b順序儲存之後填充兩個位元組用以對其,這樣一共就8個位元組。
當然,在某些時候也可以設定位元組對齊方式。這就需要使用 #pragma pack 。
#pragma pack(push) //壓棧儲存
#pragma pack(1)// 設定1位元組對齊
struct
{
char a;
short b;
char c;
}S1;
#pragma pack(pop) // 恢復先前設定
如上所示,將對其方式設為1位元組對齊,那麼S1就不填充位元組,sizeof為各元素所佔位元組之和即4。這一點在從外部2進位制檔案中讀入struct大小的資料到struct中,是很有用的.
另外,還有如下的一種方式:
· __attribute((aligned (n))),讓所作用的結構成員對齊在n位元組自然邊界上。如果結構中有成員的長度大於n,則按照最大成員的長度來對齊。
· __attribute__ ((packed)),取消結構在編譯過程中的最佳化對齊,按照實際佔用位元組數進行對齊。