【问题标题】:Structure size and memory layout depending on #pragma pack结构大小和内存布局取决于#pragma pack
【发布时间】:2014-04-23 21:37:45
【问题描述】:

考虑以下在 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. 为什么 sizeof(str_test) 对于 8 包是 12?

  2. 为什么内存布局一样,不依赖pack值?

【问题讨论】:

  • 您的“输出”不一致。你有一个 sizeof==12 和一个 10 字节的转储?
  • @harper - 对于所有包值,f3 之后的字节为 cc(调试配置中未初始化的内存)。
  • 我读到// 8 - 12 的大小是 12 字节。我只是想知道你为什么省略了尾随的CCs。 ;-)

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


【解决方案1】:

为什么第 8 包的 sizeof(str_test) 是 12?

来自MSDN docs

成员的对齐方式将位于一个边界上,该边界要么是 n 的倍数或成员大小的倍数,以 更小。

在您的情况下,最大成员是 4bytes,小于 8,因此 4bytes 将用于对齐。

为什么内存布局是一样的,不依赖于pack值?

编译器不允许重新排序结构成员,但可以填充成员。如果是 Pack 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

【讨论】:

  • 谢谢,现在我明白whichever is smaller 的意思了。但是仍然不清楚,为什么我在内存窗口中看不到 2 个字节的填充。
  • 谢谢,您的笔记Memory dump in the case of last member int 解释了一切,#2 已回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
  • 2022-12-05
  • 1970-01-01
相关资源
最近更新 更多