Bit fields in C and C++

C/C++ bit fields have been in the language since K&R’s first edition. They haven’t evolved much – maybe it’s time?

Kernighan & Ritchie’s [K&R’s] seminal book The C Programming Language [Prentice Hall, 1978] defined the first version of C, a third-generation language [3GL] that allowed a program to be written in a high-level language rather than assembly language. Its biggest advantage compared to other 3GLs (like Fortran and Pascal) was that the programmer could still use C to write hardware-specific code for device controllers and the like—the other languages abstracted much of this away.

Note that for the following posts, I tried to write the code in C and C++ agnostic syntax. Of course this is not always possible: please assume relevant definitions or compiler options to accommodate this.
For example, for g++ assume --std=c++1z, and for gcc a header file:

#ifndef __cplusplus
enum bool { false, true };
typedef enum bool bool;
#endif // !__cplusplus

My favourite example of hardware access, and the subject of this series of posts, is the C/C++ struct bit field. K&R described it (paraphrased) as “a way to name individual bits”, but they also state:

Externally-imposed data formats, such as interfaces to hardware devices, also often require the ability to get at pieces of a word.

Without

This post shows how bit fields in hardware peripheral registers are often programmed using #defines (or enums) rather than struct bit fields, along with explicit code using & and | to implement bit masking, bit insertion and extraction. It uses a real-world example—the Line Control register for the National Semiconductor 8250/16×50 Universal Asynchronous Receiver/Transmitter (UART). It also uses a contrived example to demonstrate another common construct that uses bit shifting as well.

With

This post describes how to implement the above Line Control Register using struct bit fields instead, demonstrating the efficiencies and improvements afforded; as well as how the above contrived example is improved as well.

Architecture

K&R identified the limitations with bit fields in their original book, which are a direct result of most hardware architectures rather than a result of the way the language is defined. This post discusses those limitations.

Implementation

As well as the above architecture limitations, the way the compiler implements struct bit fields is also not fully defined. So, many programmers have decided not to use bit fields, and use the bit mask, bit shift and bit insertion/extraction code described above precisely because it gives them more control. This post describes the deficiencies implicit in the compiler’s implementation of struct bit fields, over and above the limitations already detailed above.

volatile

Since a major use for struct bit fields is to access external hardware peripherals, no discussion of them can be complete without describing this necessary definition—and the implications thereof.

Show-stopper

The limitations described in the above posts can be worked around, either by changing the definition or discovering the compiler’s implementation details and leveraging them (and hoping these don’t change in a future compiler update…). But there’s one real-world scenario that makes the use of struct bit fields effectively impossible to use in that instance. This post describes that scenario.

Proposal

This final post proposes a language extension to overcome even the above show-stopper.


Comments are welcome. I suggest that generic comments on the whole “Bit fields” series and concepts go on this main page, while comments specific to a sub-page be written there.

Leave a comment