Gcc “与”的区别是什么#pragma pack“;及__属性(“对齐”)”;

Gcc “与”的区别是什么#pragma pack“;及__属性(“对齐”)”;,gcc,attributes,Gcc,Attributes,及 它们之间的区别是什么?pragma pack(字节对齐)影响由字节对齐输入指定的结构的每个成员,或影响其自然对齐边界,以较小者为准 \uuuu属性(对齐(字节对齐))影响变量的最小对齐方式(或结构字段,如果在结构中指定) 我认为以下是等效的 struct A { //... }; A a __attritube__((aligned(L1_CACHE_LINE))) 其中是一个属性((对齐(一级缓存线))将确保u int32\t A内部结构A将与2字节对齐,但不会以相同方式对齐其他变

它们之间的区别是什么?

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

\uuuu属性(对齐(字节对齐))
影响变量的最小对齐方式(或结构字段,如果在结构中指定)

我认为以下是等效的

struct A {
  //...
};

A a __attritube__((aligned(L1_CACHE_LINE)))
其中是一个
属性((对齐(一级缓存线))
将确保
u int32\t A
内部
结构A
将与2字节对齐,但不会以相同方式对齐其他变量

参考:

  • #pragma-pack
    是一种Microsoft语法,出于兼容性原因一直在使用

    \uuuu属性(对齐))
    是一种特定于GCC的语法(MSVC不支持)

    以下是差异的总结:

    • #pragma pack
      (和变体)更简洁,用GCC语法表示属性
      压缩的
      对齐的
      (见下面的示例)
      
    • #pragma pack
      适用于插入位置后放置的每个结构定义(或直到另一个
      #pragma pack
      覆盖它),而GCC
      uu属性uu
      是在本地为类型定义的
    • #pragma-pack
      的细粒度不如属性:它不能仅应用于结构的少数成员。但是,实际上,这很少是一个问题,因为对于同一个结构的成员,很少需要不同的对齐和打包设置
    以一种非常简洁的方式,
    #pragma pack(n)
    大致相当于
    uu attribute_uu((打包,对齐(n)))
    :它定义了打包(为节省内存而压缩结构)和最小对齐。因此,pragma上的
    n
    (最小对齐)

    原则上,可以使用GCC属性来模拟
    #pragma pack
    ,但不能反过来,因为属性提供了更精细的控制

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

    #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()
    
    #包括
    #包括//for offsetof()
    #pragma包(推送,4)
    结构街{
    字符c;
    双d;
    短e;
    };
    #pragma-pack(pop)//从现在起禁用#pragma-pack的效果
    结构st2{
    字符c_uuu属性_uuu((压缩,对齐(4));
    双d_uuu属性_uuu((压缩,对齐(4));
    短e_uuu属性_uuu((压缩,对齐(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在此示例中发出警告:
    “char”类型字段的“packed”属性被忽略。
    。事实上,一个更简洁、更恰当的解决方案是将
    packed
    应用于整个结构(正如@Hagai所做的),这相当于1。但是,请注意,不能简单地将
    对齐
    应用于整个结构:该行为并不等同于将
    对齐
    分别应用于每个字段

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

    1来自:

    为结构和联合类型指定压缩属性等同于在每个结构或联合成员上指定压缩属性


    在我的一个测试()中,我实际上需要向整个结构A添加
    \uuuuu attribute\uuuuu((packed))
    ,以确保两个版本中的布局相同。请确认一下,并更新代码示例好吗?如果我的测试不完整并且可能导致其他反例,我会犹豫是否这样做。这是不等价的,至少对于
    aligned(2)
    。你能说得更准确些吗?我刚刚在gcc 5.4.1和4.8.5上进行了测试,在我的示例中,将4替换为2确实为这两个结构提供了相同的结果。从您的问题来看,您似乎已将该属性应用于结构本身,而不是单独应用于每个字段。在这种情况下,它不起作用,因此我将属性分别放在每个字段中。我添加了一个说明,说明
    对齐的
    不能被分解,即使
    打包的
    可以。你是对的。我只是误读了你的答案。感谢您的澄清。主要的gcc参考文献:(1)(参见
    对齐
    对齐(对齐)
    ,和
    打包
    )和(2)(例如:
    #pragma pack(1)
    强制1字节对齐,然后是现在遵循此强制对齐的结构定义,然后是
    #pragma pack()
    禁用强制1字节对齐并返回默认值。另请参见C++11
    alignas()
    alignof()
    运算符:和。
    #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()
    
    #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));
    }