Structure Alignment in Visual C ++

Visual C ++ offers both a compiler switch ( /Zp ) and a pragma pack to affect the aligment of structure members. However, I seem to have a misconception about how they work.

According to MSDN for the given alignment value n,

The alignment of the element will be on the border, which is either a multiple of n or a multiple of the size of the member, whichever is smaller.

Assume the packet value is 8 bytes (which is the default value). Inside the structure, I think that any member whose size is less than 8 bytes will have an offset multiple of its size. Any member that is 8 bytes or more in size will have an offset multiple of 8 bytes.

Now take the following program:

 #include <tchar.h> #pragma pack(8) struct Foo { int i1; int i2; char c; }; struct Bar { char c; Foo foo; }; int _tmain(int argc, _TCHAR* argv[]) { int fooSize = sizeof(Foo); // yields 12 Bar bar; int fooOffset = ((int) &bar.foo) - ((int) &bar); // yields 4 return 0; } 

The Foo structure is 12 bytes in size. So, in Bar I would expect the Foo member to be at offset 8 (a multiple of 8), while in reality it is at offset 4. Why is this?

In addition, Foo really only has 4 + 4 + 1 = 9 bytes of data. The compiler automatically adds padding bytes at the end. But then again, given the alignment value of 8 bytes, shouldn't it be cast to a multiple of 8, not 4?

Any clarifications are appreciated!

+6
source share
3 answers

Your passage explains this, "whichever is less." On a 32-bit platform, int is 4 bytes. 4 is less than 8. Thus, it has 4-byte alignment.

The pragma pack makes things pack, not unpack. He will not be inserted if he has no reason.

+7
source

Keep in mind why alignment matters in the first place. This allows the processor to quickly read memory without the need for multiplexing bytes. The processor never reads the structure in one gulp, it accesses only its members. Thus, the fact that the Foo structure is 12 bytes is inconsequential. The only important thing is the coordination of its members. Given that the Foo element has no alignment requirement greater than 4, the Bar.foo member only needs to align to 4.

Foo equal to 12 bytes instead of 9 can also use an explanation. The compiler adds 3 bytes of padding to the end, so the Foo array still has elements correctly aligned for each element of the array.

+4
source

As your quote says, to check for 8-byte alignment, you need 8 or more byte data types. Here's a sample with some types of explicit size. In addition, by placing a small element at the end, padding will not be displayed, since it can be discarded from the end of the structure.

 #include <stdio.h> int main(int argc, char *argv[]) { struct S { __int64 a; __int8 b; __int64 c; }; #pragma pack(push,1) struct T { __int64 a; __int8 b; __int64 c; }; #pragma pack(pop) #pragma pack(push,8) struct U { __int64 a; __int8 b; __int64 c; }; struct B { __int8 c; struct U s; }; #pragma pack(pop) printf("S %d T %d U %d B %d\n", sizeof(struct S), sizeof(struct T), sizeof(struct U), sizeof(struct B)); return 0; } 

Compiling with VC 2010:

 C:\src>cl -nologo -W3 -Od packing.c && packing.exe packing.c S 24 T 17 U 24 B 32 
+1
source

Source: https://habr.com/ru/post/913777/


All Articles