Structure alignment padding, largest size of paddi

2020-05-01 08:44发布

问题:

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)
};

Thanks.

回答1:

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.



回答2:

All of the following is implementation dependent. Do not rely on this for the correctness of your programs (but by all means make use of it for debugging or improving performance).

In general each datatype has a preferred alignment. This is never larger than the size of the type, but it can be smaller.

It appears that your compiler is aligning 64-bit integers on a 32-bit boundary when compiling in 32-bit mode, but on a 64-bit boundary in 64-bit mode.

As to your question about MyBadStruct: In general, write your code to be simple and easy to understand; only do anything else if you know (through measurement) that you have a problem. Having said that, if you sort your member variables by size (largest first), you will minimize padding space.



回答3:

Typically the best way to reduce the amount of padding inserted by the compiler is to sort the data members inside of your struct from largest to smallest:

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


};

the size may vary depending on 32 vs 64 bit os because the size of a pointer will change

live version: http://coliru.stacked-crooked.com/a/aee33c64192f2fe0

i get size = 24