Search code examples
c++cstructpaddingmemory-alignment

Structure alignment padding, largest size of padding, and order of struct members


I've been learning about structure data padding since I found out my sizeof() operator wasn't returning what I expected. According to the pattern that I've observed, it aligns structure members with the largest data type. So for example...

struct MyStruct1
{
    char a;     // 1 byte
    char b;     // 1 byte
    char c;     // 1 byte
    char d;     // 1 byte
    char e;     // 1 byte
                // Total 5 Bytes

    //Total size of struct = 5 (no padding)
};

struct MyStruct2
{
    char a;     // 1 byte
    char b;     // 1 byte
    char c;     // 1 byte
    char d;     // 1 byte
    char e;     // 1 byte
    short f;    // 2 bytes
                // Total 7 Bytes
    
    //Total size of struct = 8 (1 byte of padding between char e and short f
};

struct MyStruct3
{
    char a;         // 1 byte
    char b;         // 1 byte
    char c;         // 1 byte
    char d;         // 1 byte
    char e;         // 1 byte
    int f;          // 4 bytes
                    // Total 9 bytes

    //Total size of struct = 12 (3 bytes of padding between char e and int f
};

However if make the last member an 8 byte data type, for example a long long, it still only adds 3 bytes of padding, making a four-byte aligned structure. However if I build in 64 bit mode, it does in fact align for 8 bytes (the biggest data type). My first question is, am I wrong in saying it aligns the members with the largest data type? This statement seems correct for a 64 bit build, but only true up to 4 byte data types in a 32 bit build. Has this to do with the native 'word' size of the CPU? Or the program itself?

My second question is, would the following be an entire waste of space and bad programming?

struct MyBadStruct
{
    char a;             // 1 byte
    unsigned int b;     // 4 bytes
    UINT8 c;            // 1 byte
    long d;             // 4 bytes
    UCHAR e;            // 1 byte
    char* f;            // 4 bytes 
    char g;             // 1 byte
                        // Total of 16 bytes

    //Total size of struct = 28 bytes (12 bytes of padding, wasted)
};

Solution

  • How padding is done, is not part of the standard. So it can be done differently on different systems and compilers. It is often done so that variables are aligned at there size, i.e. size=1 -> no alignment, size=2 -> 2 byte alignment, size=4 -> 4 byte alignment and so on. For size=8, it is normally 4 or 8 bytes aligned. The struct it self is normally 4 or 8 bytes aligned. But - just to repeat - it is system/compiler dependent.

    In your case it seems to follow the pattern above.

    So

    char a;
    int  b;
    

    will give 3 bytes padding to 4 byte align the int.

    and

    char a1;
    int  b1;
    char a2;
    int  b2;
    char a3;
    int  b3;
    char a4;
    int  b4;
    

    will end up as 32 byte (again to 4 byte align the int).

    But

    int  b1;
    int  b2;
    int  b3;
    int  b4;
    char a1;
    char a2;
    char a3;
    char a4;
    

    will be just 20 as the int is already aligned.

    So if memory matters, put the largest members first.

    However, if memory doesn't matter (e.g. because the struct isn't used that much), it may be better to keep things in a logical order so that the code is easy to read for humans.