Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between "#pragma pack" and "__attribute__((aligned))"

Tags:

gcc

attributes

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

A a;

and

struct A {
  //...
};

A a __attritube__((aligned(L1_CACHE_LINE)))

What's difference between them?

like image 276
大宝剑 Avatar asked Jan 06 '13 05:01

大宝剑


2 Answers

#pragma pack is a Microsoft syntax that has been ported to GCC for compatibility reasons.

__attribute__((aligned)) is a GCC-specific syntax (unsupported by MSVC).

Here's a summary of the differences:

  • #pragma pack (and variants) is more concise, and represents both attributes packed and aligned in GCC syntax (see example below);
  • #pragma pack applies to every structure definition placed after where it is inserted (or until another #pragma pack overrides it), while GCC __attribute__s are defined locally to a type;
  • #pragma pack is less fine-grained than attributes: it cannot be applied to only a few members of a struct. In practice, however, this is rarely an issue, since you'll rarely need different alignment and packing settings for the members of a same struct.

In a very concise way, #pragma pack(n) is roughly equivalent to __attribute__((packed,aligned(n))): it defines both packing (compacting structures for memory-saving purposes) and minimal alignment. Hence the n (minimal alignment) on the pragma.

In principle, #pragma pack can be emulated using GCC attributes, but not the other way around, because of the finer control given by attributes.

Here's an example you can test on GCC: the first definition uses #pragma pack and the second one uses attributes. The layout is the same in both cases.

#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 emits a warning on this example: ‘packed’ attribute ignored for field of type ‘char’. Indeed, a more concise and proper solution is to apply packed to the entire struct (as @Hagai did), which is equivalent1. Note, however, that you cannot simply apply aligned to the whole structure: the behavior is not equivalent to applying aligned to each field separately.

Note that, if you combine both (pragma + attributes) in the same structure definition, the algorithm is more complex, because it has to respect several constraints, which result in some min/max computations between (1) the alignment given by #pragma pack, (2) the member type's minimal alignment, and (3) aligned attributes declared in the field (if any).

1 From the GCC documentation:

Specifying the packed attribute for struct and union types is equivalent to specifying the packed attribute on each of the structure or union members.

like image 114
anol Avatar answered Nov 15 '22 14:11

anol


The #pragma pack(byte-alignment) effect each member of the struct as specified by the byte-alignment input, or on their natural alignment boundary, whichever is less.

The __attribute__((aligned(byte-alignment))) affect the minimum alignment of the variable (or struct field if specified within the struct)

I believe the following are equivalent

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

where is A a __attritube__((aligned(L1_CACHE_LINE))) will insure u_int32_t a inside struct A will aligned with 2 byte but will not align the other variable in the same manner.

Reference:

  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
like image 16
Hagai Avatar answered Nov 15 '22 12:11

Hagai