#pragma pack(8)应该如何工作?

时间:2016-09-07 01:16:23

标签: visual-c++ struct alignment pragma-pack

我是结构对齐和包装的新手。我以为我明白了,但我找到了一些我没想到的结果(见下文)。

我对结构对齐的理解是:

  1. 类型通常在内存地址上对齐,内存地址是其大小的倍数。

  2. 根据需要添加填充以便于正确对齐

  3. 必须将结构的末尾填充到最大元素的倍数(以便于数组访问)

  4. #pragma pack指令基本上允许根据类型的大小覆盖对齐的一般约定:

    #pragma pack(push, 8)
    struct SPack8
    {
      // Assume short int is 2 bytes, double is 8 bytes, and int is 4 bytes
      short int a;
      double b;
      short int c;
      int d;
    };
    #pragma pack(pop)
    
    Pseudo struct layout: What I expected:
    // note: PADDING IS BRACKETED
    0, 1, [2, 3, 4, 5, 6, 7] // a occupies address 0, 1
    8, 9, 10, 11, 12, 13, 14, 15, // b occupies 8-15 inclusive
    16, 17, [18, 19, 20, 21, 22, 23] // c occupies 16-17 inclusive
    24, 25, 26, 27 // d occupies 24-27 inclusive
    // Thus far, SPack8 is 28 bytes, but the structure must be a multiple of
    // sizeof(double) so we need to add padding to make it 32 bytes
    [28, 29, 30, 31]
    

    令我惊讶的是,VS 2015 x86上的sizeof(SPack8)== 24。似乎d没有在8字节地址上对齐:

    offsetof(SPack, a) // 0, as expected
    offsetof(SPack, b) // 8, as expected
    offsetof(Spack, c) // 16, as expected
    offsetof(SPack, d) // 20..what??
    

    有人可以解释一下发生了什么/我误解了什么?

    谢谢!

1 个答案:

答案 0 :(得分:2)

您的误解是#pragma pack允许您拓宽结构,但它没有。如果需要,pack允许您更紧密地打包结构。 #pragma pack(push, 8)告诉编译器,它可以最多在8字节边界上对齐,但不能更多

示例:

#pragma pack(push, 2)
struct X {
    char a; // 1 byte
    // 1 byte padding
    int b; // 4 bytes, note though that it's aligned on 2 bytes, not 4.
    char c, d, e; // 3 bytes
    //1 byte padding
}; // == 10 bytes, the whole struct is also aligned on 2 bytes, not 4
#pragma pack(pop)

// The same struct without the pragma pack:
struct Y {
    char a; // 1 byte
    // 3 bytes padding
    int b; // 4 bytes
    char c, d, e; // 3 bytes
    // 1 byte padding
};

这是pack所做的,使用 less 填充,正如编译器通常使用的那样。在您的示例中,您尝试将int与8字节边界对齐,但由于您允许编译器在最多 8字节上对齐,因此编译器将执行4字节对齐喜欢使用很好。您的整个结构体大小为24,其大小也是8(您最大的成员)的倍数,因此不需要填充填充最多32个。

你可以强制对齐你的结构

__declspec(align(32)) struct Z {
    char a;
    int b;
    char c, d, e;
};

甚至是你的结构的成员

struct SPack8
{
  // Assume short int is 2 bytes, double is 8 bytes, and int is 4 bytes
  short int a;
  double b;
  short int c;
  __declspec(align(8)) int d;
};

在特定的边界上,但我没有看到强制4字节类型在8个字节上对齐的理由。