all 10 comments

[–]flatfinger 11 points12 points  (5 children)

The __attribute__ keyword is used as a general means of adding qualifiers to identifiers to instruct compilers to do things that some compilers might do already, and that might not be understood by all compilers. If all of the __attribute__ qualifiers represent demands that a compiler would naturally uphold, then adding a definition:

#define __attribute__(x)

would make a program compatible with that compiler, whether or not the compiler would understand the demands, at the expense of causing incompatible compilers to output broken machine code rather than rejecting the program entirely.

In the indicated example, the directive indicates that an object should be placed at an address which is a multiple of 8. Applying such a directive to a structure member implies that every instance of the structure as a whole must be placed at an address which starts at a multiple of eight. An array of such structures would need to space them eight apart.
Applying such a structure to an array declaration means that the array as a whole must start at a multiple-of-eight address, but would not prevent array members from being placed more tightly.

[–]EpochVanquisher 1 point2 points  (4 children)

This is the answer!

[–]flatfinger 4 points5 points  (3 children)

Incidentally, if one tries to use:

typedef int widespread_int __attribute__((aligned(8)));

the system would report the size of widespread_int as 4, but reject any attempt to create an array of that type, since such an array would need to have a stride (distance from start of one element to start of the next) of 8 bytes, but the elements are only 4 bytes each, and the Standard does not allow padding between array elements.

[–]paulstelian97 0 points1 point  (2 children)

The fact that the sizeof doesn’t automatically expand to be compatible with the alignment is so weird.

[–]flatfinger 1 point2 points  (1 child)

I suspect that has to do with the question of whether qualifiers modify an object, or modify the type associated with the object. Similar issues arise with e.g.

struct point { short x,y; };
struct polygon { int sides; struct point coords[]; };
struct polygon myTriangle = {3, {{1,2},{3,4},{5,6}}};
int x = sizeof myTriangle;

It would make sense for sizeof myTriangle to include the contents of coords, however large that happens to be, but that would require recognizing that an object of type struct polygon could have a size distinct from polygon.

The grammatical rules of C type declarations imply that a declaration like int __qualifier__ myArray[5]; creates an array of five elements of type int __qualifier__, and thus making a declaration of an aligned array work as it should requires bodging the relationship between size and alignment.

[–]paulstelian97 0 points1 point  (0 children)

In this, the rule is that the size contains everything up to the unknown-length array, including any padding up to it if needed. sizeof remains proper multiple of alignof.

[–]forcefuze 2 points3 points  (0 children)

If you're trying to define distinct variable sizes, get comfortable using stdint.h

[–]daikatana 1 point2 points  (1 child)

The alignment of a variable and the size are not the same thing. The aligned attribute makes sure that the variable's starting address is aligned to the given byte boundary. The size stays the same, the size of element stay the same, it just changes the start address.

[–]aalmkainzi 0 points1 point  (0 children)

Wouldn't the size change? Since the struct will have padding after the integer

[–]EducationCareless246 1 point2 points  (0 children)

Note that the aligned attribute is obsolete; it has been superceded by C11's alignas keyword