Proven C Book←↑→

115 Modern C, gathered up

What to know first

chapter 56, Undefined behaviour · undefined behaviour
chapter 55, Errors and contracts · contracts
chapter 111, C in practice · the tools of practice

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

The last chapter is a survey of modern C because this book never taught C23 separately. Features of the new standard were used as a matter of course rather than given special treatment, so at the end they must be gathered once and pointed out: “of everything you have used, these are the new ones.” That is the debt this ordering created, and this is where it is paid.

By the end of this chapter

The last chapter. Chapter 111 looked round the terrain of practice, so now we gather up the road travelled. We look back over the faces of C23 this book has used naturally, organise the practices of modern C into a single sheet of guidance, and talk about where one can go from here. The book closes with a short last word.

The questions this chapter answers

  1. 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 featurewhere first metwhat it made easy
the bool, true, false keywordschapter 31judgement as a value without a header
nullptrchapter 37removing NULL’s ambiguity
two’s complement fixedchapter 6the end of worrying about the portability of sign representation
[[nodiscard]]chapters 38 and 55the compiler blocks the mistake of forgetting to check for failure
[[fallthrough]]chapter 32the intent of switch fallthrough as documentation
the ckd_add familychapter 56overflow as a value rather than UB
alignofchapter 38querying alignment requirements at the level of the language
the removal of trigraphschapter 8tidying up a scar of the character-code era
the relaxation of va_startchapter 67dropping 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.

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.