关于sizeof struct

ASK:The size of my structure is not what I expect it to be。。。

Answer:This is caused by the fact that the compiler inserts padding in different places for optimization and alignment purposes

Explanation

Structure member alignment

Suppose you have the following structure:

struct A1 { char a[2]; int b; }; 

You could think that sizeof(A1) equates to 6, but it doesn’t. It equates to 8. The compiler inserts 2 dummy bytes between members ‘a’ and ‘b’.

The reason is that the compiler will align member variables to a multiple of the pack size or a multiple of the type size, whichever is smallest.

The default pack size in visual studio is 8 bytes.

‘b’ is of the integer type, which is 4 bytes wide. ‘b’ will be aligned to the minimum of those 2, which is 4 bytes. It doesn’t matter if ‘a’ is 1, 2, 3 or 4 bytes wide. ‘b’ will always be aligned on the same address.

Structure end padding

Suppose we swap members ‘a’ and ‘b’:

struct A2 { int b; char a[2]; }; 

The compiler places ‘a’ right next to ‘b’ without padding, because the address after ‘b’ is naturally aligned for ‘a’.

Still, sizeof(A2) equates to 8. The reason is that ‘b’ still needs to be aligned on a multiple of 4 bytes if 2 structures of type A2 are placed in an array.

If nothing special was done, member ‘b’ of the second structure would be placed right after member ‘a’ of the first structure. This would not a 4 byte multiple but a 2 byte multiple.

To prevent this, the compiler pads the end of the structure with dummy bytes until the structure size is a multiple of the largest alignment in the structure. That way the alignment for all consecutive structures is valid.

This can lead to strange situations if you create custom structures without paying attention to these details. This can be illustrated with the following structure if the pack size is left to the default 8 bytes:

struct A3 { char a; double b; char c; }; 

‘a’ is 1 byte wide, and aligned to the start of the structure.

‘b’ is 8 bytes wide, but is aligned on the next address multiple of 8 bytes. This means that 7 dummy bytes are inserted between ‘a’ and ‘b’.

‘c’ is 1 byte wide, but the structure A3 itself is padded with 7 extra bytes because its size has to be a multiple of 8.

As a result, the total structure size is a whopping 24 bytes, even though there are only 10 bytes of data inside.

Programmatically controlling pack size

It is possible to control structure packing at compile time. That can be done using a pragma directive:

 #pragma pack(push, 1) struct A4 { char a; double b; char c; }; #pragma pack(pop) 

The first pragma stores the current pack setting and changes it to 1. This will cause all data members to be placed right next to each other, since the minimum of 1 byte and any member size is still 1 byte.

The structure size for this structure is not 24 anymore, but 10. Of course, since the double value is not 8 byte aligned anymore, read and write operations to it might not be as efficient anymore.

The second pragma directive will restore the global pack size to its previous setting. This way the local pack size change has no side effects in other parts of the code.

It is also possible to change the pack size and leave it like that, but that could cause problems in other parts of the code.

Additional Reading Material

Packing is explained in detail in the MSDN documentation. Refer to the following article for more information. http://msdn2.microsoft.com/en-us/library/2e70t5y1.aspx

Acknowledgements

This FAQ was contributed by Bruno van Dooren.

原文地址:https://www.cnblogs.com/gaojing/p/1583543.html