“Program testing can be used to show the presence of bugs, but never to show their absence!”
This book assumes some prior experience with the C programming language. However, the way that C is taught as a programming language and how it is used in the systems world are not always the same. As a simple example, consider the following trivial example of C code:
int maximum_size = 65536;
In many examples of systems code, this type declaration is too vague to be safe. Specifically,
according to the C language specification, there is no fixed size for the int
type. While an
int
can often be assumed (on modern laptops, desktops, or server machines) to be four bytes in
size, it doesn’t have to be. On some embedded systems, for instance, an int
is only two bytes in
size. This declaration would then be a problem, because the value 65,536 cannot be represented as
a two-byte signed integer (which range from -32,768 to 32,767). Consequently, systems programmers
typically use more explicit types that clearly indicate the exact size, such as uint32_t
(unsigned 32-bit integer).
This Appendix is intended as a re-introduction to the C language as used by this text. It is not
intended as a complete introduction for readers who have never used C before. For instance, there is
no coverage here of standard control structures, such as loops or conditional statements. We also do
not cover file-related functions (such as fopen()
) that use pointers to FILE instances, as these
functions are oriented toward ASCII-formatted text files; systems programming typically involves
working with binary-formatted data instead. Instead, this Appendix focuses on intermediate or
advanced features of C that are commonly used in systems programming. We start this Appendix with a
discussion of how to consult documentation and debugging, as these are critical skills for systems
programming.