Home > front end >  pragma pack(n) vs pragma pack(push,n)
pragma pack(n) vs pragma pack(push,n)

Time:10-29

What is the difference between

  1. pragma pack(n) and pragma pack(push,n)
  2. #pragma pack(pop) and #pragma pack()

Can someone explain through an example ? Which should be used when ?

I went through https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html#:~:text=#pragma pack(push[,,and removes that stack entry) already but looking out for more explanation.

CodePudding user response:

If you use push and pop, you can "stack" multiple packing specifications. Without, you can just return to the default:

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

struct pushed_default {
    char c;
    long l;
};
#pragma pack(push, 2)
struct pushed_2 {
    char c;
    long l;
};
#pragma pack(push, 1)
struct pushed_1 {
    char c;
    long l;
};
#pragma pack(push, 4)
struct pushed_4 {
    char c;
    long l;
};
#pragma pack(pop)
struct popped_a {
    char c;
    long l;
};
#pragma pack(pop)
struct popped_b {
    char c;
    long l;
};
#pragma pack(pop)
struct popped_c {
    char c;
    long l;
};

#pragma pack(2)
struct pack_2 {
    char c;
    long l;
};
#pragma pack(1)
struct pack_1 {
    char c;
    long l;
};
#pragma pack(4)
struct pack_4 {
    char c;
    long l;
};
#pragma pack()
struct pack_a {
    char c;
    long l;
};
#pragma pack()
struct pack_b {
    char c;
    long l;
};
#pragma pack()
struct pack_c {
    char c;
    long l;
};

int main(void) {
    printf("%zu\n\n", offsetof(struct pushed_default, l));

    printf("%zu\n", offsetof(struct pushed_2, l));
    printf("%zu\n", offsetof(struct pushed_1, l));
    printf("%zu\n", offsetof(struct pushed_4, l));
    printf("%zu\n", offsetof(struct popped_a, l));
    printf("%zu\n", offsetof(struct popped_b, l));
    printf("%zu\n\n", offsetof(struct popped_c, l));

    printf("%zu\n", offsetof(struct pack_2, l));
    printf("%zu\n", offsetof(struct pack_1, l));
    printf("%zu\n", offsetof(struct pack_4, l));
    printf("%zu\n", offsetof(struct pack_a, l));
    printf("%zu\n", offsetof(struct pack_b, l));
    printf("%zu\n", offsetof(struct pack_c, l));
}

The result talks for itself:

$ gcc -Wall -Wpedantic packed.c -O3 -s -o packed
$ ./packed 
8

2
1
4
1
2
8

2
1
4
8
8
8

You can use push and pop all the time. Especially you can #include headers with these directives without fear of breaking other pack adjustments.

This is the relevant part of the documentation:

  1. #pragma pack(push[,n]) pushes the current alignment setting on an internal stack and then optionally sets the new alignment.
  2. #pragma pack(pop) restores the alignment setting to the one saved at the top of the internal stack (and removes that stack entry). Note that #pragma pack([n]) does not influence this internal stack; thus it is possible to have #pragma pack(push) followed by multiple #pragma pack(n) instances and finalized by a single #pragma pack(pop).

Unfortunately the maximum number of pushes is not documented. However, in practice you will not reach it.

  • Related