How does `__declspec(align(#))` work?

15,336

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.

Share:
15,336
NPS
Author by

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, 2022

Comments

  • NPS
    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 does sizeof() in this code:

    __declspec(align(32)) struct aType {int a; int b;};
    sizeof(aType);
    

    return 32?

  • NPS
    NPS almost 11 years
    So does it actually change the struct's/object's size?
  • Mats Petersson
    Mats Petersson almost 11 years
    Yes, 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
    NPS almost 11 years
    Ok, 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
    Mats Petersson almost 11 years
    Ehm, 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 for bPtr[5].a = 42;...
  • NPS
    NPS almost 11 years
    MSDN says it's 8 and I checked it - it is (both aType and bType).
  • Mats Petersson
    Mats Petersson almost 11 years
    Really? 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
    NPS almost 11 years
    Why buggy? It does what is says it does.
  • Mats Petersson
    Mats Petersson almost 11 years
    It 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 or new scenario.