【问题标题】:Are structs that contain packed structs packed themselves?包含打包结构的结构是否自行打包?
【发布时间】:2018-05-09 23:46:48
【问题描述】:

假设我有一个结构,其中包含其他未打包的结构:

struct ContainerOfNonPacked
{
    NonPacked1 first;
    NonPacked2 second;
};

然后我有一个结构,其中包含其他打包的结构:

struct ContainerOfPacked
{
    Packed1 first; // declaration of struct had __attribute__((packed))
    Packed2 second; // ditto
};

第一个不会被编译器打包(即不能保证结构内不会有“洞”)。它可能巧合地没有漏洞,但这不是问题所在。

第二个包含打包结构的容器呢?是否有任何保证一个结构仅由作为其字段的打包结构组成的结构本身是打包的?

【问题讨论】:

  • 这取决于实现 - 没有“标准 C++”答案。如果firstsecond 有不同的对齐要求,那么包含结构可能在两个成员之间有填充,即使它们都被打包了。
  • 我的意思是第一个案例“不保证打包”。我知道,一般来说,总是有可能碰巧有一个打包的结构,但这不是我想要的。第二种情况实际上似乎可以保证被打包(见下面的答案):但我不是很清楚,如果你有一个更权威的答案,我会喜欢。
  • 如果您知道这是实现定义的,您介意写一个答案吗?这是非常有用的信息,尤其是因为这里唯一的答案仅使用了一个示例。谢谢!

标签: c++ struct packing


【解决方案1】:

编辑:这取决于编译器,而不是可以依赖的行为。

对于 GCC 和 clang,仅包含打包结构的结构本身就是“打包”的。它们不会有任何填充“洞”。

这里有一个例子来说明(godbolt链接:https://godbolt.org/g/2noSpP):

我们有四个结构,Packed1、Packed2、NonPacked1 和 NonPacked2。

#include <cstdint>

struct Packed1
{
    uint32_t a;
    uint64_t b;
} __attribute__((packed));

struct NonPacked1
{
    uint16_t a;
    // Padding of 2 bytes
    uint32_t b;
    uint8_t c;
};

// We have two structs of the same size, one packed and one not
static_assert(sizeof(NonPacked1) == 12);
static_assert(sizeof(Packed1) == 12);

struct Packed2
{
    uint64_t a;
    uint64_t b;
} __attribute__((packed)); // packing has no effect, but better for illustration

struct NonPacked2
{
    uint32_t a;
    // Padding of 4 bytes
    uint64_t b;
};

// And again, two structs of the same size
static_assert(sizeof(Packed2) == 16);
static_assert(sizeof(NonPacked2) == 16);

Packed1 和 Packed2 进入 ContainerOfPacked 结构,另外两个进入 ContainerOfNonPacked。

struct ContainerOfNonPacked
{
    NonPacked1 first; // 12 bytes
    // Padding of 4 bytes between the non-packed struct-fields
    NonPacked2 second; // 16 bytes
};

struct ContainerOfPacked
{
    Packed1 first; // 12
    // No padding between the packed struct-fields
    Packed2 second; // 16
};

static_assert(sizeof(ContainerOfNonPacked) == 32);
static_assert(sizeof(ContainerOfPacked) == 28);

正如代码 cmets 和静态断言所示,打包结构的容器内部没有填充孔。它的行为就好像它本身是“打包的”。

虽然这是一个答案,但我也在寻找可以引用标准相关部分或其他一些权威/理论解释的答案。

【讨论】:

  • 同时包含 Packed 和 NonPacked 的结构呢?如果你只打算询问一个只有 Packed 成员的结构,那么你应该在问题中说清楚。
  • 您好,谢谢您的建议。我已编辑问题以指定容器仅包含全部打包的成员结构。但更一般地说,我很想得到一个答案,它可以定义围绕包装的规则以及它如何“扩展”到封闭类(如果存在这样的规则)。
  • 一切由编译器决定,没有独立的规则
  • 谢谢,很高兴知道这一点。那我就不会依赖这种巧合的行为了。
猜你喜欢
  • 2021-05-29
  • 1970-01-01
  • 2015-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多