Редактировать: все зависит от компилятора и не зависит от поведения.
В случае 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);
Как показывают комментарии к коду и статические утверждения, в контейнере упакованных структур нет отверстий для заполнения. Он ведет себя так, как будто он сам "упакован".
Хотя это ответ, я также ищу ответы, которые могут привести соответствующие части Стандарта или некоторые другие авторитетные / теоретические объяснения.