“#pragma pack”和“__attribute __((aligned))”之间的区别是什么?

时间:2013-01-06 05:58:15

标签: gcc attributes

#pragma pack(L1_CACHE_LINE)
struct A {
  //...
};
#pragma pack()

A a;

struct A {
  //...
};

A a __attritube__((aligned(L1_CACHE_LINE)))

他们之间有什么区别?

2 个答案:

答案 0 :(得分:11)

#pragma pack(byte-alignment)影响结构的每个成员,由字节对齐输入或其自然对齐边界指定,以较小者为准。

__attribute__((aligned(byte-alignment)))影响变量的最小对齐(如果在结构中指定,则为结构字段)

我相信以下内容是等效的

#define L1_CACHE_LINE 2

struct A
{
    u_int32_t   a   __attribute__ ( (aligned(L1_CACHE_LINE)) );
    u_int32_t   b   __attribute__ ( (aligned(L1_CACHE_LINE)) );
    u_int16_t   c   __attribute__ ( (aligned(L1_CACHE_LINE)) );       
    u_int16_t   d   __attribute__ ( (aligned(L1_CACHE_LINE)) );      
    u_int32_t   e   __attribute__ ( (aligned(L1_CACHE_LINE)) );     
};


#pragma pack(L1_CACHE_LINE)
struct A
{
    u_int32_t   a;  
    u_int32_t   b;  
    u_int16_t   c;  
    u_int16_t   d;  
    u_int32_t   e;  
};
#pragma pack()

其中A a __attritube__((aligned(L1_CACHE_LINE)))将确保u_int32_t a内的struct A与2字节对齐,但不会以相同的方式对齐其他变量。

参考:

  1. http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=%2Fcom.ibm.vacpp6m.doc%2Fcompiler%2Fref%2Frnpgpack.htm
  2. http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/attributes-variables.html

答案 1 :(得分:7)

#pragma pack是一种Microsoft语法,出于兼容性原因,该语法为ported to GCC

__attribute__((aligned))是特定于GCC的语法(MSVC不支持)。

以下是差异的摘要:

  • #pragma pack(和变体)更简洁,在GCC语法中代表两个属性packedaligned(参见下面的示例);
  • #pragma pack适用于插入之后放置的每个结构定义(或直到另一个#pragma pack覆盖它),而GCC __attribute__在本地定义为类型;
  • #pragma pack的细粒度不如属性:它不能仅应用于结构的少数成员。然而,在实践中,这很少是一个问题,因为您很少需要对同一结构的成员进行不同的对齐和打包设置。

以非常简洁的方式,#pragma pack(n)大致相当于__attribute__((packed,aligned(n))):它定义了包装(用于节省内存的压缩结构)和最小的对齐。因此,pragma上的n(最小对齐)。

原则上,#pragma pack可以使用GCC属性进行模拟,但不是相反,因为属性给出了更精细的控制。

以下是您可以在GCC上测试的示例:第一个定义使用#pragma pack,第二个定义使用属性。两种情况下的布局都是相同的。

#include <stdio.h>
#include <stddef.h> // for offsetof()

#pragma pack(push, 4)
struct st {
  char c;
  double d;
  short e;
};
#pragma pack(pop) // disables the effect of #pragma pack from now on

struct st2 {
  char c __attribute__((packed,aligned(4)));
  double d __attribute__((packed,aligned(4)));
  short e __attribute__((packed,aligned(4)));
};

void main() {
  printf("offsetof(struct st, d) = %zu\n", offsetof(struct st, d));
  printf("offsetof(struct st2, d) = %zu\n", offsetof(struct st2, d));
  printf("offsetof(struct st, e) = %zu\n", offsetof(struct st, e));
  printf("offsetof(struct st2, e) = %zu\n", offsetof(struct st2, e));
}

GCC会针对此示例发出警告:‘packed’ attribute ignored for field of type ‘char’。实际上,更简洁和恰当的解决方案是将packed应用于整个结构(如@Hagai所做的),这相当于 1 。但请注意,您不能只是将aligned应用于整个结构:行为等同于将aligned分别应用于每个字段。

请注意,如果在同一结构定义中同时组合两个(pragma +属性),则算法会更复杂,因为它必须遵守多个约束,这会产生一些min / max (1)#pragma pack给出的对齐,(2)成员类型的最小对齐,以及(3)aligned在字段中声明的属性(如果有的话)之间的计算。

1 来自GCC documentation

  

为struct和union类型指定packed属性等同于在每个结构或联合成员上指定packed属性。

相关问题