(1). Data Alignment:
話說,個人覺得"Data alignment"的部份自己略有小著墨,但這兩三天卻被有關Data alignment的給弄掛了~狀況是這樣的,,為何傳遞的封包大小計算經sizeof(X)應該為58,但卻會大於我自己認為的大小? 經過網路上搜尋後才意識到,,對於32bit(4 Bytes)的CPU在擷取資料時會為了效率問題而執行"Data Alignment的動作, 所以儲存的資料皆為 4 Bytes的倍數為主.下列即為人家所探討的部份. (特別是下列Ex3~Ex5的解釋, 我覺得非常有意思)
http://kf99916cs.blogspot.tw/2012/10/data-structure-alignment.html
http://kezeodsnx.pixnet.net/blog/post/27585076-data-structure%E7%9A%84%E5%B0%8D%E9%BD%8A%28alignment%29
http://linyacheng.blogspot.tw/2011/10/c-data-structure-alignment.html
Data Structure Alignment 究竟是何物?
它是為了加快執行速度而有的一種方式
由於 CPU 架構的關係,在讀 memory 的時候會以一個 word 為單位(在 32-bit 系統是4 bytes 為1個 word),因此 data 在儲存時,memory offset 便會是 word size 倍數,藉此增加效能
Data Structrue Alignment 分成兩個部分:
. Data Alignment: Data Alignment 即是上述所述,data 的 memory offset 會是 word size 的倍數.
. Data Structure Padding: 在 data structure 尾巴塞入一些無意義的 bytes,使下一個 data structure 的 memory offset 能夠對齊.
在一個 32-bit 系統,常見的 C/C++ compiler 的 default alignments為:
- char (1 byte): 1-byte aligned
- short (2 bytes): 2-byte aligned
- int (4 bytes): 4-byte aligned
- float (4 bytes): 4-byte aligned
- double (8 bytes): 8-byte aligned (in windows) / 4-byte aligned (in Linux)
- Any pointer (4 bytes): 4-byte aligned
#pragma pack(push) /* push current alignment to stack */ #pragma pack(n) /* set alignment to n byte boundary */
#pragma pack() /* cancel previous alignment to n byte boundary */
#pragma pack(push) /* pop previous alignment to stack */
__attribute__ ((pack(n))) /* 要求某個structure使用pack(n) */
Ex 1: 使用系統預設的alignment下為4Bytes, 所以下列memory佔用的話是12 Bytes, 非7 Bytes.
struct align_test
{
char x; //1 byte
int y; //4 bytes
short int z; //2bytes
};
Ex 2:如果指定的 n 大於 structure 中成員的最大 size 將不起作用,仍依 size 最大的成員進行對齊。sizeof( struct D) 就會是 4 + 1 + p(1) = 6 bytes。
#pragma pack(2)
struct D {
int a;
char b;
};
#pragma pack()
Ex 3: 為了更徹底的了解系統預設alinment的行為, 請看下列解釋
Structure's Size: 12 bytes.
struct MixedData {
char data1;
short data2; int data3; char data4; };
Memory Offset:
- data1:type 是 char,char 是 1-byte aligned,意思是其 memory 位置開頭必須是1 的倍數,所以就放在 0x00 的位置(假設是從 0x00 開始)
- data2:type 是 short,short 是 2-byte aligned,所以其 memory 位置開頭必須是 2的倍數,因此 0x01 就會被放置一個 1 byte 的 padding,然後在 0x02 放 data2。因為 short size 比 char size 大,因此會 allocate 2-byte memory
- data3:同理,4-byte aligned,allocate 4-byte memory
- data4:雖然 size 是 1 byte,但由於目前最大的 alignment size 為 4 bytes,因此會 allocate 4-byte memory,後面的 3 bytes 就會是 padding
- Compiler 在 alignment 時最大原則:以目前最大的 alignment size向前 padding,向後 allocate大小.
struct ReorderedMixedData { // after reordering
char data1;
char data4; // reordered
short data2;
int data3;
};
- 在宣告 structure 時, 成員的順序其實是會有所影響的, 因此要宣告一個好的 structure,應該要減少 padding來降低 structure 的 size.
Ex 5: 設定 alignment pack size 為 1 byte, 因此原本 data2 和 data4 會出現 padding 的情況就消失了. 實際結果如下: Structure's Size: 8 bytes
#pragma pack(push) // push current alignment to stack
#pragma pack(1) // set alignment to 1 byte boundary
struct PackedData {
char data1;
short data2;
int data3;
char data4;
};
#pragma pack(pop) // restore original alignment from stack
P.S:
(a). 宣告 structure 時,成員的順序看起來沒有影響,但其實是有的,一個好的 structure 應該要減少 padding 產生,這樣便能降低 structure 的大小. (b). pack(n) 如果n比structure中最大member size還大 那還是會用最大member的size來alignment
(c). 在網路傳輸資料時, 需要用pack(1)來避免compiler作padding的動作.
#pragma pack(push) /* pop previous alignment to stack */
ReplyDeletewrong