C++ Bitfield Packing with Bools

C++ bitfield packing with bools

your compiler has arranged all of the members of test3 on integer size boundaries. Once a block has been used for a given type (integer bit-field, or boolean bit-field), the compiler does not allocate any further bit fields of a different type until the next boundary.

I doubt it is a bug. It probably has something to do with the underlying architecture of your system.

edit:

c++ compilers will allocate bit-fields in memory as follows: several consecutive bit-field members of the same type will be allocated sequentially. As soon as a new type needs to be allocated, it will be aligned with the beginning of the next logical memory block. The next logical block will depend on your processor. Some processors can align to 8-bit boundaries, while others can only align to 16-bit boundaries.

In your test3, each member is of a different type than the one before it, so the memory allocation will be 8 * (the minimum logical block size on your system). In your case, the minimum block size is two bytes (16-bit), so the size of test3 is 8*2 = 16.

On a system that can allocate 8-bit blocks, I would expect the size to be 8.

Packing bools with bit field (C++)

There is no easy, elegant method without using accessors or an interface layer. Unfortunately, there is nothing like a #pragma thing to fix this. I ended up just converting the bools to unsigned int and renaming variables from e.g. f to f_flag or f_bool to encourage correct usage and make it clear what the variables contained. It's lower-effort than Thomas's solution, but not as robust, obviously, and still gets around some of the main drawbacks with any of the easier methods.

Advantages of boolean values to bit-fields

There are several things to consider when using bitfields. Those are (order of importance would depend on situation)

  • Performance

Bitfields operation incur performance penalty when set or read (as compared to direct types). A simple example of codegen shows the extra instructions emitted: https://gcc.godbolt.org/z/DpcErN However, bitfields provide for more compact data, which becomes more cache-friendly, and that could completely outweigh any drawbacks of additional operations. The only way to understand the real performance impact is by benchmarking actual application in the real use case.

  • ABI Interoperability

Endiannes of bit fields is implementation defined, so layout of the same struct produced by two compiler can differ.

  • Usability

There is no reference binding to a bitfield, nor you can take it's address. This could affect code and make it less clear.

Can or should I make bools bit fields?

Can ... I make bools bit fields?

Yes. It is one of 3 well defined choices.

A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type. It is implementation-defined whether atomic types are permitted. C17dr § 6.7.2.1 5



.... should I make bools bit fields?

Yes, if it makes code more clear.

Note: this is one place to not use int x:1 as it is implementation defined if x has values [0,1] or [-1,0]. Use signed int x:1 or unsigned x:1 or _Bool x:1 for [-1,0], [0,1], [0,1] respectively.

For x:1, bool does have a clearer functionally specification than signed int when assigning an out-of-range value. See comment. For unsigned, just the LSbit is copied.

Is bool safe in a bitfield definition?

Yes. In practice, you can use sizeof(bool) * CHAR_BIT as your guide to knowing how many bits are available.

From C++98, § 9.6.3

A bit-field shall have integral or enumeration type (3.9.1).

From C++98, § 3.9.1.7

Types bool, char, wchar_t, and the signed and unsigned integer types are collectively called integral
types

Is it OK to force the size of a bool to 1 in a C struct?

Per C 2018 6.7.2.1 5, a bit-field may have type _Bool:

A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type…

Presuming the source includes <stdbool.h>, bool is _Bool, so the structure definition is okay.

Note that this:

test_struct my_struct = { 0 };

initializes all named members of the structure to zero. This is a result of the specification of initializers; it does not have anything to do with whether the bit-fields are packed into a single byte or not.

Will all compilers provide the expected result, i.e. use one bit to store the bool values?

Yes, the C standard requires C implementations to pack bit-fields as long as they fit in the addressable storage unit the implementation chooses to use for bit-fields, in C 6.7.2.1 11:

… If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit…

So, if you have consecutive one-bit bit-fields that fit within a byte (which must be at least eight bits), and are not preceded by other bit-fields, they must be packed into one byte.

C++ bool array as bitfield?

I would recommend using a std::bitset That way you could simply declare:

std::bitset<8> asdf;

and use it with [].

asdf[0] = true;
asdf[3] = false;

Boolean bit fields vs logical bit masking or bit shifting - C++

With the large address spaces on desktop boxes, an array of 32/64-bit booleans may seem wasteful, and indeed it is, but most developers don't care, (me included). On RAM-restricted embedded controllers, or when accessing hardware in drivers, then sure, use bitfields, otherwise..

One other issue, apart from R/W ease/speed, is that a 32- or 64-bit boolean is thread-safer than one bit in the middle that has to be manipulated by multiple logical operations.



Related Topics



Leave a reply



Submit