GCC上#pragma pack(push,n)/ #pragma pack(pop)和__attribute __((__ packed __,aligned(n)))之间有什么区别?

Cla*_*diu 11 c c++ gcc memory-alignment

特别是在GCC上(也就是说,用GCC编译),以下两种方式有什么区别?

struct foo1 {
    char a;
    int b;
} __attribute__((__packed__, aligned(n) ));
Run Code Online (Sandbox Code Playgroud)

和:

#pragma pack(push, n)
struct foo2 {
    char a;
    int b;
};
#pragma pack(pop)
Run Code Online (Sandbox Code Playgroud)

它们看起来表现不同:

foo1 f1;
foo2 f2;

int& i1 = f1.b; // ok
int& i2 = f2.b; // cannot bind packed field 'f2.foo2::b' to 'int&'
Run Code Online (Sandbox Code Playgroud)

为什么一个而不是另一个有错误?内存布局至少相同吗?

Joh*_*ger 8

你不说你正在使用的GCC的版本,但你可以找到相应的手册上线.但是,它们在这些方面都非常兼容,因为属性和编译指示一旦定义,通常会在各版本之间保持兼容性.我将从GCC 4.9.3的手册中引用具体的引文,目前是GCC 4系列的最新版本.特别是,关于类型属性结构包装编译指示的部分是相关的.

GCC手册中#pragma pack和朋友们说:

#pragma指令用于更改随后定义的结构(除零宽度位域除外),联合和类的成员最大对齐方式.

(重点补充).它说__attribute__((packed)):

附加到struct或union类型定义的此属性指定放置结构或联合的每个成员(除了零宽度位字段)以最小化所需的内存.

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

此属性指定指定类型的变量的最小对齐方式,以字节为单位.

(重点补充).

因此,不,#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));
Run Code Online (Sandbox Code Playgroud)

......可能和......有同样的效果

#pragma pack(push, n)
struct foo2 {
    char a;
    int b;
};
#pragma pack(pop)
Run Code Online (Sandbox Code Playgroud)

......,取决于n.