This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

long long bitfield layout (i686-linux-gnu)


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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]