GCC 上的#pragma pack(push, n)/#pragma pack(pop) 和 __attribute__((__packed__, aligned(n) )) 有什么区别?

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

具体在GCC上(即都用GCC编译),以下两者的工作方式有什么区别?

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

和:

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

他们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&'

为什么一个有错误,另一个没有?至少内存布局是否相同?

您没有说明您使用的是哪个版本的 GCC,但是您可以找到相关的相应手册 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

GCC 手册说 #pragma pack 和朋友:

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

(强调)。它说 __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.

它说 __attribute__ ((aligned(n))):

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

(强调已添加)。

因此,不,#pragma pack(n),有或没有push,一般来说,并不等同于将__attribute__((packed, aligned(n))附加到结构类型。前者指定受影响结构的成员在 n 字节或更细的边界上对齐。后者指定受影响结构的成员用最小允许填充填充,并且为整个结构的实例选择的对齐要求必须不少于 n。它们不仅不一样,甚至不太相似。

您应该发现影响结构定义的 #pragma pack(1) 对实例布局的影响与将 __attribute__((packed)) 附加到该结构的定义相同。然而,即使他们达到同样的目的,他们也不是同一件事。两者的行为和效果都在 C++ 规范之外,GCC 完全有权在其他方面区别对待它们。

但是,如果您想使用属性来影响结构成员的对齐方式,那么您将需要在逐个成员的基础上至少应用一些属性。例如...

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

... 可能与 ...

具有相同的效果
#pragma pack(push, n)
struct foo2 {
    char a;
    int b;
};
#pragma pack(pop)

...,取决于 n.