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

时间:2015-10-30 13:33:42

标签: c++ c gcc memory-alignment

特别是在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&'

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

1 个答案:

答案 0 :(得分:7)

您没有说明您正在使用哪个版本的GCC,但您可以找到相应的手册on-line。但是,它们在这些方面都非常兼容,因为属性和编译指示一旦定义,通常会在各版本之间保持兼容性。我将从GCC 4.9.3的手册中引用具体的引文,目前是GCC 4系列的最新版本。特别是,type attributesstructure-packing pragmas上的部分是相关的。

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));

......可能与......具有相同的效果。

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

...,取决于n