包裝結構

預設情況下,結構用 C 填充。如果要避免此行為,則必須明確請求它。在 GCC 下,它是 __attribute__((__packed__))。在 64 位計算機上考慮此示例:

struct foo {
    char *p;  /* 8 bytes */
    char c;   /* 1 byte  */
    long x;   /* 8 bytes */
};

該結構將自動填充到 has8-byte 對齊,如下所示:

struct foo {
    char *p;     /* 8 bytes */
    char c;      /* 1 byte  */

    char pad[7]; /* 7 bytes added by compiler */

    long x;      /* 8 bytes */
};

所以 sizeof(struct foo) 會給我們 24 而不是 17。這是因為 64 位編譯器在每個步驟中以 8 位元組的字對儲存器進行讀/寫操作,並且當嘗試在儲存器中寫入 char c; 時,顯而易見的是一個完整的 8 位元組(即字)取出並僅消耗第一個位元組它及其七個連續的位元組保持為空,並且對於結構填充的任何讀寫操作都不可訪問。

結構包裝

但是如果新增屬性 packed,編譯器將不會新增填充:

struct __attribute__((__packed__)) foo {
    char *p;  /* 8 bytes */
    char c;   /* 1 byte  */
    long x;   /* 8 bytes */
};

現在 sizeof(struct foo) 將返回 17

通常使用包裝結構:

  • 為了節省空間。
  • 格式化資料結構以通過網路傳輸,而不依賴於網路的每個節點的每個架構對齊。

必須考慮到某些處理器(如 ARM Cortex-M0)不允許未對齊的記憶體訪問; 在這種情況下,結構打包可能導致未定義的行為並可能導致 CPU 崩潰。