#gcc/g++ bitfields produce wrong size
1 messages · Page 1 of 1 (latest)
dont know why i didnt narrow it down before but this is just bitfields
gcc/g++ bitfields produce wrong size
This particular example does not seem to produce sizeof(u) == 8 on any actual compiler 🤷
I tested the following code on https://godbolt.org/ (it can be compiled both as C and C++):
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
struct u {
bool c : 1;
bool d : 1;
bool e : 1;
uint64_t f : 2;
} __attribute__((packed));
size_t test(void) {
return sizeof(struct u);
}
Most GCC and clang versions consider sizeof(struct u) to be 1; even some more obscure compilers like icc, icx and zig c++ give the same result. The major exceptions are MinGW GCC (all available versions give 9) and MinGW clang (all available versions give 16).
Technically the bit field packing is implementation defined, and GCC documents many of those details as “determined by ABI”; the fact that __attribute__((packed)) is a GCC extension also complicates things (because the code cannot be compiled under MSVC to test its behavior).
Although it is possible to use pragmas which are supported by MSVC instead of __attribute__((packed)):
#pragma pack(1)
struct u {
bool c : 1;
bool d : 1;
bool e : 1;
uint64_t f : 2;
};
#pragma pack()
In this case the behavior of MSVC, MinGW GCC and MinGW clang becomes the same — sizeof(struct u) == 9. So apparently the difference is that in the Windows ABI for a packed struct the bool and uint64_t bit fields don't get packed together, and the uint64_t bit field always occupies the full uint64_t size, even though that leaves some bytes completely unused.
And also MinGW clang looks buggy (it accepts the packed attribute used by GCC, but does not produce the same result as GCC for the same platform).
😅 the static assert to a size of 8 bytes was left from the code in which the problem first occured to me but i didnt want to post that code so i made a simpler example.
do i understand it right that it is not possible to pack a bitfield tightly like with gcc on windows then?
If you make all fields uint64_t instead of using bool, they all will be packed into a single uint64_t on Windows (and apparently into a single byte on Linux).
Usually bit fields with a different base type don't get packed together, but apparently the bool case may be handled specially in some cases.
The packed attribute removes some of those “different base type” restrictions on many platforms, but apparently not on Windows.