包装结构

默认情况下,结构用 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 崩溃。