2009年8月6日 星期四

結構(struct)的大小問題

在記憶體配置的時候,因為效率考量,預設會依照元素大小整數倍的對齊
並且會以其中最大的元素為單位,配置整數倍的記憶體
例如同樣是char, short, int三個元素

struct t1
{
char c; /// 0000000x
short s; /// 0000xx00
int i; /// xxxx0000
};

struct t2
{
int i; /// 0000xxxx
short s; /// 00xx0000
char c; /// 0x000000
};

struct t3
{
short s; /// 0000000000xx
int i; /// 0000xxxx0000
char c; /// 000x00000000
};


這時候宣告出來的結構物件,大小會是8,8,12
在t1中的short,因為需要從偶數位置開始,所以會跳過1直接由2開始
而t3中的int則是因為需要從四的倍數開始,所以跳過2,3直接從4開始
三個結構的最大單元都是int,所以預留記憶體大小的時候都會是四的倍數

從上面的例子可以看出記憶體不連續的狀態,進而造成大小判斷錯誤
所以在宣告的時候最好依照大小作配置,才比較不會出現記憶體的空缺

不過,如果是對記憶體非常侷限的設備,為了避免記憶體的浪費
或是一些可讀性的考量,所以配置的方式並不能依照大小排列
這時候會需要將多出的記憶體空缺給填滿(改變對齊方式)
將struct宣告改寫成

#pragma pack(1) /// force alignment to 1 byte
struct t1
{
char c; /// 000000x
short s; /// 0000xx0
int i; /// xxxx000
};
#pragma pack() /// set alignment back to default

強制要求程式以1byte為單位對齊,大小就會變成7
並在宣告後,將預設的單位設回來(否則會出現warning)

如果是在C#裡面,則改成

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct t1
{
char c; /// 000000x
short s; /// 0000xx0
int i; /// xxxx000
};


--
參考資料
如何控制.NET Framework 2.0 中的資料欄位的實體配置
#pragma pack和數據對齊問題
C#-struct實例字段的內存佈局(Layout)和大小(Size)

沒有留言:

張貼留言