Search code examples
c++classpaddingmemory-alignment

Influence class alignment to pack variables tightly


Suppose such structs: A is out of our control but we can change the B structure:

struct A {
  int64_t x;  // 8 bytes
  int32_t y;  // 4 bytes
              // 4 padding bytes
};

struct B {
  A a;        // 16 bytes
  int32_t z;  // 4 bytes
              // 4 padding bytes (alignof(B) == alignof(A) == 8)
};
static_assert(sizeof(B) == 24);  // 8 useless bytes!

Is there a way to put z inside A padding (some attributes)?


Solution

  • Reuse of padding is determined by the ABI, not the standard or the compiler. For example, on Linux this will work:

    struct A {
      int64_t x;  // 8 bytes
      int32_t y;  // 4 bytes
                  // 4 padding bytes
      A() = default;   // <-- CHANGE HERE
    };
    
    struct B {
      [[no_unique_address]] A a; // <-- CHANGE HERE
      int32_t z;  // 4 bytes in the padding of A
    };
    
    static_assert(sizeof(B) == 16);
    

    godbolt

    A needs certain properties true of its type in order to be eligible for tail padding reuse. For this ABI, it needs to be not a POD as of C++03. Adding a user-declared constructor is sufficient.

    Then within B, we need to induce the use of tail padding. For example, if A is a base class, it will reuse its tail padding. Alternatively, using [[no_unique_address]] accomplishes the same.