How does `__declspec(align(#))` work?
Solution 1
The size of the object is used to calculate offsets in arrays and when you use pointers, so sizeof(x)
must always be a multiple of the alignment value. In this case, 1 x 32. But if you have __declspec(align(32)) struct aType {int a[12]; };
, then the size would be 2 x 32 = 64, since sizeof(a) is 12 x 4 = 48. If we change it to align to 4, 8 or 16, it would be 48.
The way it actually works is that the compiler adds an unamed padding member after the named members of the structure, to fill the structure to it's alignment size.
If it didn't work this way, something like:
aType *aPtr = new aType[15];
aPtr[12].a = 42;
wouldn't work right, since the compiler will multiply 12
by sizeof(aPtr)
to add to aPtr
internally.
Solution 2
The documentation is either poorly written or my command of the English as a foreign language is not up to par with it.
// make a nice 16 align macro
#ifndef ALIGN16
#define ALIGN16 __declspec(align(16))
#endif
// align the structure
struct ALIGN16 CB {
ALIGN16 bool m1; // and
ALIGN16 int m2; // align
ALIGN16 int m3; // each
ALIGN16 short m4; // element
};
// now it performs as expected
printf("sizeof(CB) %d\r\n", sizeof(CB));
CB vCb;
printf("CB: %p, %%%d\r\n", &vCb, (UINT_PTR)&vCb % 16);
printf("CB.m1: %p, %%%d\r\n", &vCb.m1, (UINT_PTR)&vCb.m1 % 16);
printf("CB.m2: %p, %%%d\r\n", &vCb.m2, (UINT_PTR)&vCb.m2 % 16);
printf("CB.m3: %p, %%%d\r\n", &vCb.m3, (UINT_PTR)&vCb.m3 % 16);
printf("CB.m4: %p, %%%d\r\n", &vCb.m4, (UINT_PTR)&vCb.m4 % 16);
The __declspec(align(#))
only affects the alignment of the structure and the sizeof()
, NOT each of the members in it. If you want each property to be aligned, you need to specify the alignment at member level.
I also initially assumed that a struct-level __declspec(align())
affects it and it's members but it does not. So if you want per member alignment, you need to be specific.
NPS
"That is the Most Clever UML question in stackoverflow I see so far :-)" Hippias Minor contact: the.real.nps (at) gmail (dot) com
Updated on June 04, 2022Comments
-
NPS almost 2 years
Yes, I have read this: http://msdn.microsoft.com/en-us/library/83ythb65.aspx But it's not clear to me. First of all,
__declspec(align(#))
makes every object (in a structure) declared with it start at an aligned offset. That part is clear. The aligment is also 'inherited' by the structured the object is in. But it doesn't change the object's size, does it? Precisely, why doessizeof()
in this code:__declspec(align(32)) struct aType {int a; int b;}; sizeof(aType);
return
32
? -
NPS almost 11 yearsSo does it actually change the struct's/object's size?
-
Mats Petersson almost 11 yearsYes, the
struct
is now 32 bytes long. 8 bytes for the two integers and 24 of those bytes are "filler" to fill the blank space between the first and second aType object in an array, for example. -
NPS almost 11 yearsOk, but then why here:
struct aType {int a; int b;}; typedef __declspec(align(32)) struct aType bType;
it only changes the alignment and not the size (MSDN, "Defining New Types with __declspec(align(#))")? -
Mats Petersson almost 11 yearsEhm, I bet
sizeof(bType)
will be 32... Although I don't have MS compiler available on my Linux box, so I can't easily test it. Otherwise,bType *bPtr = malloc(sizeof(bType) * 10);
would not produce a block of memory that is suitable forbPtr[5].a = 42;
... -
NPS almost 11 yearsMSDN says it's 8 and I checked it - it is (both
aType
andbType
). -
Mats Petersson almost 11 yearsReally? That must make it broken in my example code then? Or MS's docs are buggy - which wouldn't be the first time (or unique to MS).
-
NPS almost 11 yearsWhy buggy? It does what is says it does.
-
Mats Petersson almost 11 yearsIt is buggy because the code I posted above will not work - sizeof must be 32 for an object to be aligned to 32 bytes and still work in a
malloc
ornew
scenario.