Closed Malcolm-Cohen closed 2 years ago
Ok, it seems that gcc changed the way it behaves on Windows, sometime after 4.5.3...
...there is an option "-mno-ms-bitfields", and apparently that was the default back in 4.5.3 (or the mingw64 build I was using set that as a default), but the default is now -mms-bitfields.
Sorry if I wasted anyone else's time.
If a bitfield is preceded by a non-64-bit-aligned member that is not itself a bitfield, the bitfield gets 64-bit-aligned instead of beginning immediately after the previous member (which is what should happen). Actually, it also happens at least sometimes when the preceding member is a bitfield, but I have not investigated fully just what the conditions are.
This bug does not occur on much older gccs on Windows (e.g. mingw64's 4.5.3). It does not happen with any gcc on Linux to my knowledge (tried various, up to 11.2.1). It happens with tdm-gcc and msys2 gcc.
Here is a program that demonstrates the problem. This prints "... ok" three times on e.g. Linux (or with older gccs), and "FAIL ..." with tdm-gcc and msys2 gcc.
include
include
include
include
typedef struct s { uint64_t bottom; uint32_t middle; uint16_t top; unsigned exponent:15; unsigned sign:1; } Ieee128_uint_native; int main() { union { unsigned char x[24]; struct s y; } z; if (offsetof(struct s,bottom)==0 && offsetof(struct s,middle)==8 && offsetof(struct s,top)==12 && sizeof(Ieee128_uint_native)==16) printf("offsets and sizes ok\n"); else printf("FAIL offsets or sizes wrong\n"); printf("%d %d %d %d\n",(int)offsetof(struct s,bottom),(int)offsetof(struct s,middle), (int)offsetof(struct s,top),(int)sizeof(Ieee128_uint_native)); memset(&z,0,sizeof(z)); z.y.bottom = 13; if (z.x[0]!=13) printf("FAIL not little-endian\n"); z.y.bottom = 0; z.y.sign = 1; if (z.x[15]!=0x80) printf("FAIL sign bit not set in the correct place\n"); else printf("sign bit ok\n"); if (z.x[16]|z.x[17]|z.x[18]|z.x[19]|z.x[20]|z.x[21]|z.x[22]|z.x[23]) printf("FAIL high bits set\n"); printf("%x %x %x %x %x %x %x %x : %x %x %x %x %x %x %x %x :: %x %x %x %x\n", z.x[0],z.x[1],z.x[2],z.x[3],z.x[4],z.x[5],z.x[6],z.x[7], z.x[8],z.x[9],z.x[10],z.x[11],z.x[12],z.x[13],z.x[14],z.x[15], z.x[16],z.x[17],z.x[18],z.x[19],z.x[20],z.x[21],z.x[22],z.x[23]); memset(&z,0,sizeof(z)); z.y.exponent = 7; if (z.x[14]!=7) printf("FAIL exponent bits not set in the correct place\n"); else printf("exponent bits ok\n"); if (z.x[16]|z.x[17]|z.x[18]|z.x[19]|z.x[20]|z.x[21]|z.x[22]|z.x[23]) printf("FAIL high bits set\n"); printf("%x %x %x %x %x %x %x %x : %x %x %x %x %x %x %x %x :: %x %x %x %x\n", z.x[0],z.x[1],z.x[2],z.x[3],z.x[4],z.x[5],z.x[6],z.x[7], z.x[8],z.x[9],z.x[10],z.x[11],z.x[12],z.x[13],z.x[14],z.x[15], z.x[16],z.x[17],z.x[18],z.x[19],z.x[20],z.x[21],z.x[22],z.x[23]); return 0; }