# 結構體的記憶體對齊 - pragma pack `#pragma pack` 是 C/C++ 中的一個預處理器指令,用於控制結構體 (struct) 成員的記憶體對齊 (memory alignment) 方式。調整對齊會影響結構體的大小以及 CPU 存取成員的效率。 > 參考資料:[GNU-gcc-doc-6.60.8](https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Structure-Packing-Pragmas.html) ## 主要用法 1. **`#pragma pack(n)`** * **作用**: 將後續定義的結構體成員對齊方式設定為 `n` 位元組。`n` 通常是 1, 2, 4, 8 等 2 的冪。 * **`#pragma pack(1)`**: 特殊情況,表示**緊密打包 (tight packing)**,成員之間沒有填充位元組 (padding)。 * **影響範圍**: 從該指令出現開始,直到遇到下一個 `#pragma pack` 指令或檔案結尾。 2. **`#pragma pack()`** * **作用**: 取消先前設定的 `n` 值,恢復到編譯器**預設的對齊**規則。 3. **`#pragma pack(push, n)`** * **作用**: 1. 將當前的對齊設定**壓入堆疊 (push)** 保存。 2. 將對齊方式設定為 `n` 位元組(同 `#pragma pack(n)`)。 * **用途**: 常用於**臨時改變**某個區塊的對齊設定,方便之後恢復。 4. **`#pragma pack(pop)`** * **作用**: 從堆疊中**彈出 (pop)** 先前保存的對齊設定,並恢復它。 * **用途**: 必須與 `#pragma pack(push, n)` **成對使用**,用於恢復 `push` 指令之前的對齊狀態,適合局部調整結構體對齊。 ## 範例說明 1. **使用 push/pop 進行緊密打包** ```c= #pragma pack(push, 1) // 保存當前對齊, 並設定為 1 位元組對齊 typedef struct{ char c[3]; // 3 bytes int num[256]; // 假設 int 為 4 bytes, 則為 1024 bytes } test1; #pragma pack(pop) // 恢復 push 之前的對齊設定 ``` * **對齊**: 1 位元組 (無填充) * **大小**: 3 + (4 * 256) = 3 + 1024 = 1027 bytes * **優點**: 節省記憶體空間。 * **缺點**: CPU 存取 int 陣列時可能需要處理未對齊的記憶體位址,潛在降低效能。 2. 使用預設對齊 ```c=7 typedef struct{ char c[3]; // 3 bytes int num[256]; // 1024 bytes (假設 int 為 4 bytes) } test2; ``` * **對齊**: 編譯器預設值 (通常會填充以優化存取) * **大小**: * c[3] 佔用 3 bytes。 * 為了讓 num[0] (int) 對齊到 4 位元組邊界,編譯器在 c 後面**填充 1 byte**。 * num 佔用 1024 bytes。 * 總大小 = 3 + 1 (padding) + 1024 = 1028 bytes * **優點**: CPU 存取成員 (特別是 int 陣列) 時效率較高,因為它們位於自然對齊的位址。 * **缺點**: 可能會因填充而佔用較多記憶體空間。 ```c=11 void main(){ test1 *struc1 = (test1 *)malloc(sizeof(test1)); test2 *struc2 = (test2 *)malloc(sizeof(test2)); printf("struc1 size: %d\n", sizeof(test1)); // 預期輸出: 1027 printf("struc2 size: %d\n", sizeof(test2)); // 預期輸出: 1028 (依編譯器預設對齊而定) free(struc1); free(struc2); }
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up