Search code examples
c++classoopmemory-managementalignment

Relationship between alignment of class fields and alignment of object instances in C++?


Given the following C++ class:

class X {
public:
    uint8_t a;
    uint32_t b[256] __attribute__((aligned(32)));
};

How can the compiler ensure that the storage for b is 32-byte aligned, when an instance of X is presumably word-aligned? Does the aligned attribute only specify alignment relative to the object instance start address? If so, what is the right way to make b 32-byte aligned relative to the address space? Should I simply specify object instance alignment using using class alignof(32) X {...}?


Solution

  • The standard says following:

    [basic.align/2]

    A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported by the implementation in all contexts, which is equal to alignof(std​::​max_­align_­t) ([support.types]). The alignment required for a type may be different when it is used as the type of a complete object and when it is used as the type of a subobject. [Example 1:

    struct B { long double d; };
    struct D : virtual B { char c; };
    

    When D is the type of a complete object, it will have a subobject of type B, so it must be aligned appropriately for a long double. If D appears as a subobject of another object that also has B as a virtual base class, the B subobject might be part of a different subobject, reducing the alignment requirements on the D subobject. — end example]

    And [dcl.align/5]:

    The combined effect of all alignment-specifiers in a declaration shall not specify an alignment that is less strict than the alignment that would be required for the entity being declared if all alignment-specifiers appertaining to that entity were omitted.

    [Example 1:
    struct alignas(8) S {};
    struct alignas(1) U {
     S s;
    };  // error: U specifies an alignment that is less strict than if the alignas(1) >were omitted.
    — end example]
    

    So, from the above section (especially the explanations of the examples) it can be assumed that the alignment of an object is resolved to the strictest amongst its members.

    class X {
    public:
        uint8_t a;
        alignas(32) uint32_t b[256];
    };
    
    int main() {
        X x1;
        // alignas(16) X x; // Clang error: requested alignment is less than minimum alignment of 32 for type 'X'    
        alignas(64) X x2; // OK 
        alignof(X); // 32
        alignof(x1); //32
        alignof(x2); //64
        alignof(x2.b); //32
        return 0;
    }