结构大小和内存布局取决于#pragma pack

时间:2014-03-18 09:42:08

标签: c++ visual-studio-2010 visual-c++ memory-alignment pack

考虑在VC ++ 2010中编译的以下程序:

#pragma pack(push, 1)    // 1, 2, 4, 8
struct str_test
{
    unsigned int n;
    unsigned short s;
    unsigned char b[4];
};
#pragma pack(pop)

int main()
{
    str_test str;
    str.n = 0x01020304;
    str.s = 0xa1a2;
    str.b[0] = 0xf0;
    str.b[1] = 0xf1;
    str.b[2] = 0xf2;
    str.b[3] = 0xf3;

    unsigned char* p = (unsigned char*)&str;
    std::cout << sizeof(str_test) << std::endl;
    return 0;
}

我在return 0;行设置断点并在调试器中查看内存窗口,从地址p开始。我得到以下结果(sizeof和内存布局,具体取决于pack):

// 1 - 10    (pack, sizeof)
// 04 03 02 01 a2 a1 f0 f1 f2 f3

// 2 - 10
// 04 03 02 01 a2 a1 f0 f1 f2 f3

// 4 - 12
// 04 03 02 01 a2 a1 f0 f1 f2 f3

// 8 - 12
// 04 03 02 01 a2 a1 f0 f1 f2 f3

两个问题:

  1. 为什么{8}包装8的sizeof(str_test)为12?

  2. 为什么内存布局相同且不依赖于包价值?

1 个答案:

答案 0 :(得分:3)

  

为什么sizeof(str_test)对于包8来说是12?

来自MSDN docs

  

成员的对齐将位于a的边界上   n的倍数或成员大小的倍数,以两者为准   小。

在你的情况下,最大的成员是4字节,小于8,所以4字节将用于对齐。

  

为什么内存布局相同且不依赖于包值?

编译器不会被允许重新排序struct成员,但可以填充成员。如果是第8组,则执行以下操作;

#pragma pack(push, 8)    // largest element is 4bytes so it will be used instead of 8
struct str_test
{
    unsigned int n; // 4 bytes
    unsigned short s; // 2 bytes        
    unsigned char b[4]; // 4 bytes
    //2 bytes padding here;
};
#pragma pack(pop)

因此sizeof(str_test)将为12。

好吧,似乎编译器(MSVC2010)根据类型更改填充位置,在unsigned char b[4];的情况下,它在结构的末尾放置了两个字节填充。在您的情况下,2个字节cc cc恰好位于字符数组之后。

#pragma pack(push, 8)    // largest element is 4bytes so it will be used instead of 8
struct str_test
{
    unsigned int n; // 4 bytes
    unsigned short s; // 2 bytes 
    //2 bytes padding here;       
    int;  // 4 bytes

};
#pragma pack(pop)

我所做的是将最后一个成员从char[4]更改为int,并且可以通过分别减去案例6和8中最后一个成员和第一个成员的地址进行验证。

最后一个成员int的情况下的内存转储如下

04 03 02 01 a2 a1 cc cc f0 f1 f2 f3

最后一个成员unsigned char[4]的情况下的内存转储如下

04 03 02 01 a2 a1 f0 f1 f2 f3 cc cc