长久以来,我都有这样一个观念,比如 pack(4),就代表着所有数据都是以 4 字节对齐的,直到我有了 64 位机,并且看到下面这个例子:

    struct One {
        double d;
        char c;
        int i;
    };

    struct Two {
        char c;
        double d;
        int i;
    };

如果按 4 字节对齐的话,按我的观点,结构体中每一个成员都应该以 4 字节对齐,那么两个都是 4+8+4=16, 结果是对的。

那么如果按 8 字节对齐的话,结果是不是应该是 8+8+8=24?

可是错了。

正确的结果应该是 sizeof(struct One) = 16, sizeof(struct Two) = 24

为什么不一样呢?

pragma pack(n) 它指定了结构成员按 n(1,2,4,8,16)字节对齐,但它并不是指结构体中的每个成员都要按 n 对齐,而是按照每个成员的大小(align 值)和 n 相比较小的值对齐。

结构体还有另外一个需求,就是其大小必须是其成员 align 值最大者的整数倍。

那么上面的两个不同就很好解释了:

    struct One {
        double d; // 8 字节对齐占第 0-7 字节
        char c;   // 1 字节对齐占第 8 字节,另外 9-11 字节用于下面 int 对齐
        int i;    // 4 字节对齐占第 12-15 字节,16 是 8 的倍数,不需要 padding
    };

    struct Two {
        char c;   // 1 字节对齐占第 0 字节,另外 1-7 字节用于下面 double 对齐
        double d; // 8 字节对齐占 8-15 字节
        int i;    // 4 字节对齐占 16-19 字节,20 不是 8 的倍数,需要加 4 个字节 padding
    };

各种类型变量的 align 值可参考 Data Structure Alignment

再举一个结构体嵌套的例子:

    struct Four
    {
        short s;
        long l;
    };

    struct Five
    {
        char c;
        struct Four four;
        short s;
    };

sizeof(struct Four)sizeof(struct Five) 在 4 字节对齐和 8 字节对齐时分别是多少呢?

我们以 8 字节对齐为例:

    struct Four
    {
        short s; // 2 字节对齐占第 0-1 字节,另外 2-7 字节用于下面 long 对齐
        long l;  // 8 字节对齐占第 8-15 字节
    }; // sizeof(struct Four) = 16

    struct Five
    {
        char c;            // 1 字节对齐占第 0 字节,另外 1-7 字节用于下面 four 对齐
        struct Four four;  // 8 字节对齐,占第 8-23 字节,结构体以其成员最大 align 值对齐
        short s;           // 2 字节对齐,占第 24-25 字节,26 不是 8 的倍数,需外加 6 字节
    }; // sizeof(struct Five) = 32

如果在 32 位机中,struct Four 中,long 长度为 4, 于是 sizeof(struct Four) = 8, 并且最大 align 值是 4.

于是在 struct Five 中,four 是按 4 字节对齐的,虽然是 pack(8),但 4<8, 所以选 4 作为 align 值,sizeof(struct Five) = 16.

以上所有实验结果来自 x86_64 GNU/Linux,gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-48)。