在 C 語言和 C++ 中,__attribute__((packed))
?是一種用于數據結構體的編譯器擴展屬性,這個屬性主要用于修改結構體的內存對齊行為。
背景知識:結構體內存對齊
在許多計算機架構中,編譯器會自動對數據進行對齊(alignment),也就是說,數據在內存中的地址會遵循一定的對齊規則。這是為了提升數據訪問的效率,因為許多處理器在訪問對齊的內存地址時速度更快。通常,結構體的每個成員會根據其數據類型按照某種對齊規則進行對齊,同時整個結構體也會有自然對齊值,以適應其最大成員類型的對齊要求。
對齊帶來的問題 & 解決:
默認情況下,結構體中的每個成員會在內存中按照其對齊要求進行排列,這可能會導致在兩個成員之間出現空閑的字節(稱為填充字節),從而浪費一些內存空間。這種內存的浪費在嵌入式系統或者對內存占用敏感的應用場景中可能會被認為不可接受。
使用?__attribute__((packed))
?的意義
__attribute__((packed))
?是 GCC 編譯器的一個擴展功能,用于要求編譯器對指定的數據結構取消默認的對齊填充。- 有了?
packed
?屬性,編譯器會盡量緊密排列結構體的成員,將數據結構的大小減小到可能的最小值,即所有的字段按照聲明的順序緊密排列,而不插入任何額外的填充字節。
應用情境:
- 節省內存:在一些內存受限的環境中,例如某些嵌入式系統。
- 數據協議格式固定:結構體用于與特定格式的存儲或通信協議(例如文件格式或網絡數據包)進行交互,確保數據對齊和結構體內存布局一致性。
__attribute__((packed))
?或?#pragma pack
?會禁用對齊,緊湊排列結構體的成員。
以下是代碼示例:
#include <stdio.h>#pragma pack(push, 1) // 設置為1字節對齊
struct packed_struct {char a; // 1字節int b; // 4字節short c; // 2字節
};
#pragma pack(pop) // 恢復默認對齊struct normal_struct {char a; // 1字節int b; // 4字節short c; // 2字節
};int main() {printf("Size of normal_struct: %zu bytes\n", sizeof(struct normal_struct));printf("Size of packed_struct: %zu bytes\n", sizeof(struct packed_struct));return 0;
}
代碼解析
normal_struct
:- 系統會自動對齊結構體成員,默認對齊方式通常基于成員最大類型的大小(如
int
為4字節、short
為2字節)。 char a
占用1字節,但后面會填充3字節(以滿足int
的對齊要求)。int b
?正常對齊,占用4字節。short c
?后面可能還會補齊額外字節(如果需要),使結構體總大小為int
的倍數。
- 系統會自動對齊結構體成員,默認對齊方式通常基于成員最大類型的大小(如
packed_struct
:- 禁用了默認對齊規則,結構體的成員按緊湊方式存放。
- 泄露的空間被完全消除,每個成員緊跟前一個成員存儲。
運行結果(可能因平臺不同而異)
假設在一個系統中:
int
是4字節,short
是2字節,char
是1字節。
運行結果可能如下:
Size of normal_struct: 12 bytes
Size of packed_struct: 7 bytes