size and alignment of int bitfields

338 views Asked by At

A struct with bitfields, even when "packed", seems to treat a bitfield's size (and alignment, too?) based on the specified int type. Could someone point to a C++ rule that defines that behavior? I tried with a dozen of compilers and architectures (thank you, Compiler Explorer!) and the result was consistent across all.

Here's the code to play with: https://godbolt.org/z/31zMcnboY

#include <cstdint>

#pragma pack(push, 1)
struct S1{ uint8_t  v: 1; }; // sizeof == 1
struct S2{ uint16_t v: 1; }; // sizeof == 2
struct S3{ uint32_t v: 1; }; // sizeof == 4
struct S4{ unsigned v: 1; }; // sizeof == 4
#pragma pack(pop)

auto f(auto s){ return sizeof(s); }

int main(){
    f(S1{});
    f(S2{});
    f(S3{});
    f(S4{});
}

The resulting ASM clearly shows the sizes returned by f() as 1, 2, 4 for S1, S2, S3 respectively: enter image description here

2

There are 2 answers

3
eerorika On BEST ANSWER

Could someone point to a C++ rule that defines that behavior?

Nothing about #pragma pack(push, 1) is specified by the standard (other than #pragma being specified as a pre-processor directive with implementation defined meaning). It is a language extension.

This is what the standard specifies regarding bit fields:

[class.bit]

... A bit-field shall have integral or (possibly cv-qualified) enumeration type; the bit-field semantic property is not part of the type of the class member. ... Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.

It's essentially entirely implementation defined or unspecified.

3
Red.Wave On

Minimum size of a bit-field sequence is that of its underlying type. Multiple adjacent bit-fields of same underlying type are packed to the minimum number of word of underlying type, without fracturing any bit-field. a bit-field of 0 size indicates an explicit break and following fields start from next word. mixed underlying types result in breaks at the point of divergence. Bits are not the minimum addressable unit on most machines and size of data types is measured in units of octets as the smallest addressable memory unit.