Visual Studio 2008 - 关于 C++ 中的结构填充

visual studio 2008 - Regarding structure padding in c++

本文关键字:结构 填充 C++ 关于 Studio 2008 Visual      更新时间:2023-10-16

我在项目中使用数据结构,在狭隘结构的上下文中,我对结构填充有疑问。首先看看下面给出的结构。我使用Visual Studio 2008编译器。

typedef struct tagDATA_PACK
{
   DWORD dDataLength;
   BYTE bFlags;
   BYTE bAttrib;
   BYTE bOffset;
}DATA_PACK;

问题1:上述结构的大小是多少? 它显示 8 个字节。这是正确的。但

考虑下面给出的修改后的结构?

typedef struct tagDATA_PACK
{
   DWORD dDataLength;
   BYTE bFlags;
}DATA_PACK;

这里的大小与上面的 8 字节结构相同。我的疑问是,编译器会在哪里添加额外的 3 字节?是在 BYTE bFlags 之后还是之前?

非常感谢您的所有回答。

标准未指定结构和类的对齐和填充。这完全取决于编译器。但是,所有健全的编译器都遵循底层平台 ABI。在您的情况下,平台是Windows,并且遵守Windows平台ABI。

在这种情况下,两个结构的填充都在最后一个成员之后。第一个结构有一个额外的填充字节,第二个结构有三个额外的填充字节。

结构中最大的类型大小为 4。这意味着整体大小将是 4 的倍数。对于这两种结构,容纳结构的 4 的最小倍数是 8。

每种数据类型都有一个对齐属性。4 字节数据类型的对齐方式为 4。2 字节数据类型的对齐方式为 2。对齐方式为 4 的类型在放置在距结构开头的 4 字节偏移量上时对齐。对齐方式为 2 的类型在放置在距结构开头的 2 字节偏移量上时对齐。等等。

成员

放置在最小偏移处,该偏移量同时遵循成员的声明顺序和成员的对齐属性。

有关结构内部填充的示例,请考虑此结构

struct MyStruct
{
   char c;
   int i;
};

c的对齐方式为 1,i的对齐方式为 4。因此,c放置在 1 字节边界上,i必须放置在 4 字节边界上。这意味着c的偏移量为 0,然后有 3 个填充字节,然后i将以偏移量 4 布局。

编译器

想要的任何地方。 如果它很重要,无论如何你都在做一些不可移植的事情,那么为什么它很重要呢?

虽然所有说这取决于编译器的答案都是正确的,因为它取决于编译器,但语言规范对布局施加了一些限制。这些限制适用于 C 中的所有结构、C++03 中的"纯旧数据"(这基本上意味着只使用 C 中的功能)和 C++11 中的"标准布局"结构(允许具有构造函数和析构函数)。限制是:

  • 重新解释-)将指向结构的指针强制转换为第一个成员的类型,生成指向第一个成员的有效指针 (C++11 §9.2/20)。这意味着在第一个成员之前不能有填充。
  • 如果联合中的两个结构具有相同的初始部分(相同类型的成员以
  • 相同的顺序),并且联合通过其中一个进行初始化,则可以通过另一个结构访问这些初始成员 (C++11 §9.2/19)。这意味着成员偏移量可能仅取决于在其之前声明的成员。

对标准布局的限制很重要。对于具有基类或虚拟成员的类,两者都不成立。

现在,当与不浪费内存的愿望相结合时,这实际上只剩下一个实用的算法,因此所有编译器都使用它。这并不意味着所有编译器都会为相同的输入生成相同的布局,因为各种基元类型的大小和对齐要求因平台而异。算法为:

  • 在偏移量 0 处布置第一个成员。
  • 在第一个可用偏移处布置每个跟随成员,可由其所需的对齐方式整除。
  • 将结构的大小舍入到任何成员的最大对齐方式的下一个倍数。
  • 结构的对齐要求是任何杆件的最大对齐。

(我几乎可以肯定MSDN的MSVC++在某处描述了这一点,但无法快速找到它)

看看这个:

typedef struct myTagDATA_PACK3
{
    char c;
    double d;
    int i;
}DATA_PACK3;

它显示 24 个字节。那是:双精度:8 字节。int : 4 字节 + (4 字节填充) = 8 字节。字符:1 字节 +(7 字节填充)= 8 字节。


总计:24 字节。