# 結構體的記憶體對齊 - 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
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.