Hello, gcc's (or clang's for that matter) layout of "long long" bitfields on i686-linux-gnu is confusing me... In some tests (see below and attachment), bitfields with "long long" type can cross 4-byte aswell as 8-byte alignment boundaries without using __attribute__((packed)). Tested with a gcc 4.9.2 from Ubuntu and a gcc 4.8.1 from OpenSUSE: struct T1 { unsigned long long a : 31; unsigned long long b : 2; }; struct T2 { unsigned long long a : 63; unsigned long long b : 2; }; Setting b's bits to all 1 in both structs, and then reading out the struct's bytes one-by-one, shows how the bitfields were layed out: | 0 1 2 3 | 4 5 6 7 | 8 9 10 11 <- byte offsets T1: | -- -- -- 80 | 01 -- -- -- (sizeof = 8) T2: | -- -- -- -- | -- -- -- 80 | 01 -- -- -- (sizeof = 12) ("--" means all-zero byte, from bitfield "a" and tail padding) This shows that T1.b crosses a 4-byte boundary, and T2.b crosses an 8-byte boundary. I didn't expect that, because normally the rule (according to the SysV ABI) is that bitfields must be allocated in a "storage unit" corresponding to the type, without crossing the "unit boundaries". I thought "long long" bitfields would at least respect 4-byte boundaries, since I think that's the natural alignment used for "long long" on i686-linux-gnu. On the other hand, I think, the i386 SysV ABI doesn't mention "long long" bitfields, so it may not be applicable... but still, I'm wondering whether the behaviour is intended. (for what it's worth, clang gave the same results) Thanks, Daniel
#include <stdio.h> #define TEST(abits, bbits) \ { \ struct T { \ unsigned long long a : abits; \ unsigned long long b : bbits; \ }; \ \ struct T t = { 0 }; \ t.b = (1ull << bbits) - 1; \ \ printf("%2i + %2i: ", abits, bbits); \ unsigned char *p = (unsigned char *)&t; \ unsigned int i; \ for (i = 0; i < sizeof(t); i++) { \ if ((i % 4) == 0) { \ printf("| "); \ } \ if (p[i] == 0) { \ printf("-- "); \ } else { \ printf("%02x ", p[i]); \ } \ } \ printf(" sizeof=%i\n", (int)sizeof(struct T)); \ } int main(int argc, char** argv) { TEST(31, 2); TEST(31, 33); TEST(31, 34); TEST(63, 2); TEST(63, 33); TEST(63, 34); return 0; }