gcc “#pragma pack”和“__attribute__((aligned))”之间的区别是什么

jckbn6z7  于 2022-11-13  发布在  其他
关注(0)|答案(3)|浏览(219)
#pragma pack(L1_CACHE_LINE)
struct A {
  //...
};
#pragma pack()

A a;

struct A {
  //...
};

A a __attritube__((aligned(L1_CACHE_LINE)))

它们之间有什么区别?

qcuzuvrc

qcuzuvrc1#

#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))),非常简洁:它定义了 packing(压缩结构以节省内存)和minimal alignment。因此,编译指示上有n(minimal alignment)。
原则上,#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应用于整个结构:该行为"不“等同于将X1 M17 N1 X分别应用于每个字段。
请注意,如果将两者合并(pragma + attributes),则该算法更为复杂,因为它必须遵守几个约束,这导致在(1)由#pragma pack指定的对齐方式,(2)成员型别的最小对齐方式,以及(3)字段中宣告的aligned属性(如果有的话)。
1从GCC documentation
为结构和联合类型指定packed属性等效于为每个结构或联合成员指定packed属性。

odopli94

odopli942#

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

其中是A a __attritube__((aligned(L1_CACHE_LINE)))将确保struct A内的u_int32_t 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
aiazj4mn

aiazj4mn3#

我没能得到和其他答案一样的结果。答案也许比目前所说的更微妙。

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

// Unaligned
struct st0 {
    int16_t total;
    int8_t d, e;
};

// Use MS pack
#pragma pack(push, 4)
struct st1 {
    int16_t total;
    int8_t d, e;
};
#pragma pack(pop)

// Align and pack individual attributes
struct st2 {
    int16_t total __attribute__((packed,aligned(4)));
    int8_t d __attribute__((packed,aligned(4)));
    int8_t e __attribute__((packed,aligned(4)));
};

// Align and pack individual attributes and entire struct
struct st3 {
    int16_t total __attribute__((packed,aligned(4)));
    int8_t d __attribute__((packed,aligned(4)));
    int8_t e __attribute__((packed,aligned(4)));
} __attribute__((packed,aligned(4)));

// Align and pack only the struct
struct st4 {
    int16_t total;
    int8_t d, e;
} __attribute__((packed,aligned(4)));

struct blah0 {
    int8_t a;
    struct st0 s;
};

struct blah1 {
    int8_t a;
    struct st1 s;
};

struct blah2 {
    int8_t a;
    struct st2 s;
};

struct blah3 {
    int8_t a;
    struct st3 s;
};

struct blah4 {
    int8_t a;
    struct st4 s;
};

void main() {
    printf("offsetof(struct st0, d) = %zu\n", offsetof(struct st0, d));
    printf("offsetof(struct st1, d) = %zu\n", offsetof(struct st1, d));
    printf("offsetof(struct st2, d) = %zu\n", offsetof(struct st2, d));
    printf("offsetof(struct st3, d) = %zu\n", offsetof(struct st3, d));
    printf("offsetof(struct st4, d) = %zu\n", offsetof(struct st4, d));
    printf("\n");
    printf("offsetof(struct st0, e) = %zu\n", offsetof(struct st0, e));
    printf("offsetof(struct st1, e) = %zu\n", offsetof(struct st1, e));
    printf("offsetof(struct st2, e) = %zu\n", offsetof(struct st2, e));
    printf("offsetof(struct st3, e) = %zu\n", offsetof(struct st3, e));
    printf("offsetof(struct st4, e) = %zu\n", offsetof(struct st4, e));
    printf("\n");
    printf("offsetof(struct blah0, s) = %zu\n", offsetof(struct blah0, s));
    printf("offsetof(struct blah1, s) = %zu\n", offsetof(struct blah1, s));
    printf("offsetof(struct blah2, s) = %zu\n", offsetof(struct blah2, s));
    printf("offsetof(struct blah3, s) = %zu\n", offsetof(struct blah3, s));
    printf("offsetof(struct blah4, s) = %zu\n", offsetof(struct blah4, s));
}

// Results in (compare with st1 and blah1).
//
// offsetof(struct st0, d) = 2
// offsetof(struct st1, d) = 2
// offsetof(struct st2, d) = 4
// offsetof(struct st3, d) = 4
// offsetof(struct st4, d) = 2
//
// offsetof(struct st0, e) = 3
// offsetof(struct st1, e) = 3
// offsetof(struct st2, e) = 8
// offsetof(struct st3, e) = 8
// offsetof(struct st4, e) = 3
//
// offsetof(struct blah0, s) = 2
// offsetof(struct blah1, s) = 2
// offsetof(struct blah2, s) = 4
// offsetof(struct blah3, s) = 4
// offsetof(struct blah4, s) = 4
//

这是在gcc(Ubuntu 11.2.0- 19 ubuntu 1)11.2.0中实现的。

相关问题