---
# System prepended metadata

title: 結構體的記憶體對齊 - pragma pack
tags: [C]

---

# 結構體的記憶體對齊 - 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);
}