#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?
#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?
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:
__attribute__((packed))
to the whole struct A to ensure the layout in both versions was the same. Could you please confirm that, and update the code example? I hesitate to do so in case my test is incomplete and could lead to other counterexamples. –
Ferraro #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.
aligned(2)
. See #43135890 –
Hesitate aligned
cannot be factored, even if packed
can. –
Ferraro 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:
__attribute__((packed))
to the whole struct A to ensure the layout in both versions was the same. Could you please confirm that, and update the code example? I hesitate to do so in case my test is incomplete and could lead to other counterexamples. –
Ferraro I fail to get the same results as in the other answers. The answer is perhaps more subtle than currently stated.
#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
//
This is with gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0.
© 2022 - 2024 — McMap. All rights reserved.
aligned
,aligned (alignment)
, andpacked
) and (2) gcc.gnu.org/onlinedocs/gcc/Structure-Layout-Pragmas.html (ex:#pragma pack(1)
to force 1-byte-alignment, followed by a struct definition which now follows this forced alignment, followed by#pragma pack()
to disable forced 1-byte-alignment and return to default. – Azotizealignas()
andalignof()
operators: en.cppreference.com/w/cpp/language/alignas and en.cppreference.com/w/cpp/language/alignof, respectively. – Azotize