12

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?

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
NPS
  • 6,003
  • 11
  • 53
  • 90

2 Answers2

14

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.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • So does it actually **change** the struct's/object's size? – NPS Aug 10 '13 at 20:17
  • 2
    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. – Mats Petersson Aug 10 '13 at 20:19
  • 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](http://msdn.microsoft.com/pl-pl/library/83ythb65.aspx), "Defining New Types with __declspec(align(#))")? – NPS Aug 10 '13 at 20:23
  • 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;`... – Mats Petersson Aug 10 '13 at 20:27
  • MSDN says it's 8 and I checked it - it is (both `aType` and `bType`). – NPS Aug 10 '13 at 20:28
  • 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). – Mats Petersson Aug 10 '13 at 20:29
  • Why buggy? It does what is says it does. – NPS Aug 10 '13 at 20:58
  • 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. – Mats Petersson Aug 10 '13 at 23:15
9

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.

CodeAngry
  • 12,760
  • 3
  • 50
  • 57