ESR (Eric S. Raymond) 寫了一篇 C Compiler 對 struct 實際如何佔用記憶體空間的說明:「The Lost Art of C Structure Packing」,全文在「The Lost Art of C Structure Packing」。
以前都學過也都還記得,但沒用就不容易想起來...
以文章裡的例子用這個 struct 說明:
struct { char *p; char c; int x; };
(下面就不列出 struct 的部份了)
實際上在記憶體裡面會因為 alignment requirement 的關係,多了一個 padding (pad
):
char *p; /* 4 or 8 bytes */ char c; /* 1 byte */ char pad[3]; /* 3 bytes */ int x; /* 4 bytes */
而如果 x 是 8 bytes 的 long 時:
char *p; char c; long x;
padding 會變成:
char *p; /* 8 bytes */ char c; /* 1 byte char pad[7]; /* 7 bytes */ long x; /* 8 bytes */
這是因為硬體架構的關係。有些是因為硬體只支援切齊 alignment 的存取指令,有些是因為效率的差異而預設會增加 padding。
在處理 protocol 這類必須依照原始的 struct 設計時,需要指定
#pragma pack
強迫 compiler 關掉,不然 compiler 還是會補上 padding。
而在一般的情況下,調整 struct 裡元素的位置就能夠在不影像存取效能的前提下節省空間,如果是大量的 struct 時效果就會變得很明顯...
GCC / Clang 可以用 __attribute__ ((packed))
可以的話最好還是重排一下 struct 的元件
一般 protocol 在設計的時候都會考慮 alignment 問題吧
而且沒事亂 pack, compile 出來的 code 在那邊 shift 來 shift 去會讓你想殺人