Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the differences between #pragma pack(push, n)/#pragma pack(pop) and __attribute__((__packed__, aligned(n) )) on GCC?

On GCC specifically (that is, compiling both with GCC), what are the differences between the way the following two work?

struct foo1 {
    char a;
    int b;
} __attribute__((__packed__, aligned(n) ));

and:

#pragma pack(push, n)
struct foo2 {
    char a;
    int b;
};
#pragma pack(pop)

They appear to behave differently:

foo1 f1;
foo2 f2;

int& i1 = f1.b; // ok
int& i2 = f2.b; // cannot bind packed field 'f2.foo2::b' to 'int&'

Why is there an error in one yet not the other? Are the memory layouts the same, at least?

like image 405
Claudiu Avatar asked Oct 30 '15 13:10

Claudiu


1 Answers

You don't say which version of GCC you're using, but you can find the appropriate manual on-line. They're all pretty compatible in these regards, however, inasmuch as the behavior of attributes and pragmas, once defined, is normally maintained across versions for compatibility. I'll draw specific quotations from the manual for GCC 4.9.3, currently the latest available version from the GCC 4 series. In particular, the sections on type attributes and on structure-packing pragmas are relevant.

The GCC manual says of #pragma pack and friends:

#pragma directives that change the maximum alignment of members of structures (other than zero-width bit-fields), unions, and classes subsequently defined.

(emphasis added). It says of __attribute__((packed)):

This attribute, attached to struct or union type definition, specifies that each member (other than zero-width bit-fields) of the structure or union is placed to minimize the memory required.

It says of __attribute__ ((aligned(n))):

This attribute specifies a minimum alignment for variables of the specified type, measured in bytes.

(emphasis added).

Thus, no, #pragma pack(n), with or without push, does not, in general, mean the same as attaching __attribute__((packed, aligned(n)) to the structure type. The former specifies that members of affected structures be aligned on n-byte or finer boundaries. The latter specifies that members of the affected structure be packed with the minimum permissible padding, and that the chosen alignment requirement for instances of the overall structure must be no less than n. Not only are those not the same, they're not even very similar.

You should find that #pragma pack(1) affecting a structure definition has the same effect on the layout of instances as does attaching __attribute__((packed)) to that structure's definition. Even if they accomplish the same end, however, they are not the same thing. The behavior and effects of both are outside the C++ specification, and GCC is entirely within its rights to treat them differently in other respects.

If you want to use attributes to influence the alignment of structure members, however, then you will need to apply at least some attributes on a member-by-member basis. For example ...

struct foo1 {
    char a;
    int b __attribute__((aligned(n)));
} __attribute__((packed));

... might have the same effect as ...

#pragma pack(push, n)
struct foo2 {
    char a;
    int b;
};
#pragma pack(pop)

..., depending on n.

like image 104
John Bollinger Avatar answered Oct 11 '22 20:10

John Bollinger