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, forg++
assume--std=c++1z
, and forgcc
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 #define
s (or enum
s) 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.