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

大宝剑*_*大宝剑 22 attributes gcc

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

A a;
Run Code Online (Sandbox Code Playgroud)

struct A {
  //...
};

A a __attritube__((aligned(L1_CACHE_LINE)))
Run Code Online (Sandbox Code Playgroud)

他们之间有什么区别?

Hag*_*gai 12

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

__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()
Run Code Online (Sandbox Code Playgroud)

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


ano*_*nol 10

#pragma pack是出于兼容性原因而已移植到GCC的Microsoft语法.

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

以下是差异的摘要:

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

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

原则上,#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));
}
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会就此例子发出警告:‘packed’ attribute ignored for field of type ‘char’.实际上,一个更简洁和正确的解决方案是应用于packed整个结构(如@Hagai所做的),这相当于1.但请注意,您不能简单地应用于aligned整个结构:行为等于aligned单独应用于每个字段.

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

1来自GCC文件:

为struct和union类型指定packed属性等效于在每个结构或union成员上指定packed属性.