Search code examples
c++gccstructg++pragma

Struct packing in GCC on 32-bit doesn't work?


I have inherited some third-party code in a project. It's comprised of a header file and a binary library without sources, so I cannot just recompile it with different settings.

The header uses a compile-time assert-like trick (typedefing a negative-size array if expression fails) to ensure proper struct alignment, but it doesn't seem to work in 32-bit mode.

Here's a stand-alone little program that captures the entire problem:

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

#pragma pack(push, 8)
struct test {char _; long long a;};
typedef char pack_test[(offsetof(test, a) == 8) ? 1 : -1];
#pragma pack(pop)

int main(int argc, char *argv[])
{
        printf("%d\n", offsetof(test, a));
        return 0;
}

The code above fails to compile both on clang 3.0 and on any recent gcc version I could quickly lay my hands on (4.5 to 4.7): the packing pragmas simply have no effect whatsoever. The compiler keeps aligning the member a to 4 bytes (you can check that by commenting the typedef out).

Why is that? How can I fix the code so that this assertion doesn't fail and keep it compatible with the ABI while not having to go over all the structs in the header and tacking attributes onto their tails?


Solution

  • On a 32-bit system, a long long may not need an alignment of eight bytes, four should be enough. After all, you still fetch two entire words from memory, whether the first of them is eight-byte aligned or four.

    You can try to force eight byte alignment with an attribute

    struct test { char _; long long a __attribute__ ((aligned(8))); };
    

    (probably wrong, I'm not familiar with gcc's attributes)

    Of course, you can also add a dummy member to the struct to ensure the desired alignment

    struct test { char _; char dummy[7]; long long a; }
    

    That should work in practice.