'Bizarre struct member packing in 32-bit clang

I stumbled upon a very bizarre struct member packing in 32-bit clang. Here is the link to the compiler explorer experiment.

In essence, I have the following structs:

struct _8Bytes
{
    uint64_t _8bytes;
};
struct _16Bytes : _8Bytes
{
    uint32_t  _4bytes;
};
struct Test : _16Bytes
{
    uint8_t test;
};

The sizeof(_16Bytes) is 16 as expected, however offsetof(Test, test) is 12 because the compiler decided to pack it right after _16Bytes::_4bytes. This is extremely annoying and I would like to disable this behavior in the first place, however so be it.

What puzzles me is if I change the _16Bytes struct as follows:

struct _16Bytes
{
    // Same as Test1::_16Bytes, but 8 bytes is now a member
    uint64_t _8bytes;
    uint32_t  _4bytes;
};

then all the sudden offsetof(Test, test) is 16. This makes absolutely zero sense to me - can somebody explain what is going on?

More importantly, is there a way to disable this annoying packing behavior?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source