115 Modern C, gathered up
What to know first
Looking back
Chapter 1 declared this book “not an introduction written by the inertia of old usage but an introduction setting out from today’s C”. Then, now that the book has been read through, how does the C the reader has learned differ from the old C?
A. It is not that the list of syntax differs but that the criterion differs. A book of old usage teaches “write it this way and it works”, while this book taught “write it this way and it is within the contract” — initialise before use (chapter 24), handle the boundary and the size together (chapter 39), check for failure through returned values (chapter 55), avoid shortcuts outside the contract (chapter 56), check with tools (chapter 18). C23′s new syntax appeared as tools that make that criterion easier to keep. The retrospect below lists those features.
The need for this chapter, and its context
By the end of this chapter
The questions this chapter answers
- Where should one go from here?
115.1 Retrospect — the C23 already used#
This book did not introduce the new standard separately but used it naturally where it was needed. Gathered together it comes to this much.
| C23 feature | where first met | what it made easy |
|---|---|---|
the bool, true, false keywords | chapter 31 | judgement as a value without a header |
nullptr | chapter 37 | removing NULL’s ambiguity |
| two’s complement fixed | chapter 6 | the end of worrying about the portability of sign representation |
[[nodiscard]] | chapters 38 and 55 | the compiler blocks the mistake of forgetting to check for failure |
[[fallthrough]] | chapter 32 | the intent of switch fallthrough as documentation |
the ckd_add family | chapter 56 | overflow as a value rather than UB |
alignof | chapter 38 | querying alignment requirements at the level of the language |
| the removal of trigraphs | chapter 8 | tidying up a scar of the character-code era |
the relaxation of va_start | chapter 67 | dropping a redundant argument from va_start |
Table 115.1 — What C23 brought, and where we met it
One direction is visible — contracts more explicit, mistakes caught sooner. This table is the concrete content of chapter 1′s “C itself is showing signs of change”.
115.2 The practices of modern C — one sheet of guidance#
Compressing this whole book into practical precepts gives this.
Building and tools. Turn the warnings on (-Wall -Wextra). Run tests with sanitizers (ASan, UBSan). Where possible, cross-check with two compilers (chapter 18).
Declarations and types. Initialise at the point of declaration. Leave what will not change as const. Where the size is a contract, use the fixed-width types of <stdint.h>. Keep sizes and indexes consistently in the size_t family (chapter 30′s trap of mixing signedness).
Memory. Boundaries are always explicit — an array and its length travel together. Confirm a pointer’s validity before using it. For dynamic allocation, settle the owner, and set the pointer to null after freeing. Solve it with automatic lifetime where possible (chapters 39 and 46).
Errors. Report failure as a value, and check return values. Internal invariants with assert, what came from outside with checks at run time (chapter 55).
Contracts. Judge not by “it ran on my computer” but by “is it correct on the abstract machine” (chapters 13 and 56).
Components. Know the contracts of the standard library and choose accordingly, and lay components with checking built in over the repeated danger zones (chapter 76 and Part XIII).
Q. Where should one go from here?
A. Three branches are recommended. Depth — the places this book has left the door open to: data structures and algorithms (chapter 47′s linked structures), concurrency (chapter 13′s multicore, and the threads and C11 atomics of chapters 94–95), systems programming (files and networks are the world of platform APIs). Breadth — the neighbouring languages: when looking at C++, Rust or Zig, the sense of memory, contracts and representation learned in this book translates over as it stands (as foretold in chapter 1). Practice — reading directly the source of the projects named in chapter 111. Well-written C code like SQLite or curl is a textbook in which every theme of this book is alive in the flesh.
And it is worth remembering too that the standard document itself has now become a text you can read — seen through the viewpoint of “a contract”, it becomes clear why that curt document was written as it was.
115.3 The appendices — a bridge beyond this book#
The main text ends here, but the book goes on a little further: the seventeen appendices at the back. Before you open them, a word on what they are.
What the appendices gather are topics too awkward to fit in the main text, yet ones you will meet sooner or later if you want a deep understanding of the places where C is actually used. The main text has walked within the contract called standard C, so stories tied to a particular operating system, chip or tool were never allowed to grow beyond a box. But work where C mostly lives — operating systems, embedded systems, system tools, performance-critical code — and you cannot avoid the machine beneath that contract. The appendices sketch that ground roughly and briefly. Each takes a subject that deserves a book of its own and cuts it to a few dozen pages, so much is left out, and much of it changes with the machine and the tools.
So do not read the appendices as finished textbooks. Think of them as links that carry you beyond this book. When an appendix catches your interest, cross over to the standard documents, datasheets and specialist books it points to. The appendices’ job is only to make that first step feel less strange.
The appendices come in three groups.
- Lookup tables (appendices A–F). Operators, formats, implicit conversions, the standard library, the grammar, the changes in C23. What the main text taught as a story, folded back into tables. There is no need to read them through; open them when you get stuck while writing code.
- Deeper into the machine (appendices G–N). Reading a dump, C without an operating system, wires and buses, disks, executable formats, booting, measurement, the machinery that governs memory. Each goes one layer further down into the real machine sketched in Part II. They are ordered so that the earlier ones supply material for the later — booting comes after disks and executable formats, and measuring the cost comes after the structure.
- Beyond this book (appendices O–P). What the wall of “I have learned it all and still cannot build anything” really is and the roads in front of it, and then further reading and how to obtain the standard document.
The last, appendix Q, lists the tables and figures in this book.
115.4 Books to read next, and the standard document#
For readers who will not stop here, further reading has been gathered separately — that is appendix P. C is a language whose shelf is unusually empty right after the introductory books, but over the last few years books filling that shelf have been appearing. The appendix notes those books’ strengths and weaknesses, together with how actually to obtain the standard document this book has all along called “the contract” (buying it, and downloading the free drafts).
And if what stalls is not the reading but the building, appendix O is that place. It names the wall of “I have learned all of C and still cannot build anything”, and sets out the roads you can choose in front of it.
115.5 Finally#
This book began in chapter 2 by drawing the computer as three parts. That picture promptly collapsed honestly — memory became a ladder, execution overlapped, an editor cut in — and what remained in its place was the contract. That knowing C is not memorising syntax but being able to read that contract is the one thing this book wanted to say.
To the reader who has come this far by reading alone, only one thing now remains — writing what was read as your own code. May the journey be a good one.