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 (typedef
ing 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 attribute
s onto their tails?
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.