Appendix Q — List of tables and figures
Every table and figure in the book, in order. The numbers, titles and pages are not written by hand but taken from the text itself, so this list changes whenever the text does. In the PDF, the number is a link to the table or figure.
Tables#
- Table 0.1 — The beginner’s pace
- Table 0.2 — Where the returning reader should look first
- Table 2.1 — The representation efficiency of three whole-number bases
- Table 2.2 — Small values where base 3 wins instead
- Table 2.3 — Voltage levels crowd together as the radix grows
- Table 2.4 — Which radix is ‘most efficient’ depends on what you count
- Table 4.1 — Two layers for reading null — the notation in source and the representation in memory
- Table 5.1 — The four regions of memory and what each is like
- Table 5.2 — The axes that separate static, stack and heap
- Table 5.3 — This chapter’s words and the standard’s words
- Table 5.4 — Machines where this sketch does not hold
- Table 5.5 — Where the four regions come back
- Table 7.1 — How the bits of
floatanddoubleare divided - Table 7.2 — The special values reserved at the two ends of the exponent
- Table 7.3 — The same numbers as 64-bit representations
- Table 8.1 — The numbers ASCII and EBCDIC gave the same characters
- Table 8.2 — Where EBCDIC’s alphabet breaks, and what sits in the gaps
- Table 8.3 — Classifying a character by hand versus asking the library
- Table 8.4 — UTF-8′s bit layout by byte count
- Table 8.5 — The names the standard gives the character sets
- Table 8.6 — The translation phases where character sets change
- Table 8.7 — The encoding names C23 tidied up
- Table 8.8 — String literal prefixes and what each guarantees
- Table 10.1 — What the operating system gives a process
- Table 10.2 — The states a process sits in
- Table 10.3 — The two modes
- Table 10.4 — Program and process — what to remember
- Table 11.1 — Candidate answers to “when do we cut off?”
- Table 11.2 — Ways of taking turns
- Table 11.3 — What has to be carried across a switch
- Table 11.4 — What the timer interrupt does
- Table 11.5 — Two ways to send one byte
- Table 11.6 — Two ways to notice that something happened outside
- Table 11.7 — The order of events in an interruption
- Table 11.8 — What happens when several things interrupt
- Table 11.9 — The windows a device keeps open
- Table 11.10 — Five ways code copes when interrupts overlap
- Table 11.11 — Interrupts and multitasking
- Table 11.12 — What interrupts did in the DOS years
- Table 11.13 — Where the ideas of this chapter lead
- Table 12.1 — The memory ladder — size and latency by tier
- Table 13.1 — What this book calls a grey zone, and what it does not
- Table 13.2 — Grey-zone practices and where each is treated
- Table 13.3 — Questions that raise the cost of a grey zone
- Table 13.4 — The ladder for handling a grey zone
- Table 13.5 — The standard’s stance and what it promises instead
- Table 13.6 — What to write down when a grey zone is used
- Table 16.1 — Terminal, shell, prompt — the words sorted out
- Table 16.2 — What the terminal does and what the shell does
- Table 16.3 — How to tell which shell you are in
- Table 16.4 — The shell commands used on day one
- Table 16.5 — Which key to press, by situation
- Table 16.6 — The forms a path can take
- Table 16.7 — The first build command, per compiler
- Table 16.8 — The same job, spelled per compiler
- Table 17.1 — Kinds of error, by stage of compilation
- Table 18.1 — Tools that need no installation
- Table 18.2 — The compiler options that settle character sets
- Table 18.3 — The four links where Hangul breaks
- Table 18.4 — The gdb commands used most
- Table 19.1 — The abbreviations in this chapter
- Table 19.2 — C compilers in active service
- Table 19.3 — What gets said about GCC and Clang
- Table 19.4 — Win32′s strengths and what they cost
- Table 19.5 — What a toolchain contains
- Table 19.6 — The stories behind the compiler names
- Table 19.7 — Official documentation, per compiler
- Table 19.8 — Embedded compilers in one line each
- Table 21.1 — The bases an integer constant can be written in
- Table 21.2 — The suffixes of an integer constant
- Table 21.3 — Where the C23 digit separator works and where it does not
- Table 21.4 — Character constant prefixes and their types
- Table 21.5 — The kinds of escape sequence
- Table 21.6 — The suffixes of a floating constant
- Table 21.7 — String literal prefixes and their encodings
- Table 21.8 — What the things that look like constants really are
- Table 21.9 — Where a
const intis refused - Table 21.10 — Four kinds of ‘constant’ and what each lacks
- Table 21.11 — Where
constexprmay be used - Table 21.12 — What the two compilers do when the value does not fit exactly
- Table 23.1 — The slots of a conversion specification and their names
- Table 23.2 — The conversions used on day one
- Table 23.3 — Three output functions and where each fits
- Table 25.1 — Declaration and definition — what we did
- Table 25.2 — Where a prototype goes
- Table 25.3 — What is forbidden in a function, and why
- Table 26.1 — What
fgetspromises - Table 26.2 — Reading the result from what the buffer’s end looks like
- Table 27.1 — What a type settles
- Table 27.2 — Object types and function types
- Table 27.3 — What an incomplete type cannot do
- Table 27.4 — The basic types, as the standard has them
- Table 27.5 — The three character types
- Table 27.6 — The clauses that make
boolan integer type - Table 27.7 — The collective names the standard gives types
- Table 27.8 — Derived types — what comes from what
- Table 27.9 — What each type qualifier promises
- Table 27.10 — Type qualifiers and storage-class specifiers, side by side
- Table 27.11 — What
constprotects, depending on where it sits - Table 27.12 — The vocabulary of types and where each is gathered
- Table 27.13 — The three families of
<stdint.h> - Table 27.14 — Choosing the integer type that fits the place
- Table 27.15 — The standard’s words and the chapter that faces each
- Table 28.1 — The minimum ranges the integer types guarantee, and their limit macros
- Table 28.2 — The floating-point limit macros
- Table 28.3 — How the type of a suffixless constant is settled
- Table 28.4 — Measured types when the same value is written differently
- Table 28.5 — The kinds of overflow
- Table 29.1 — What each arithmetic operator demands of its operands
- Table 29.2 — Shift, case by case
- Table 33.1 — The three loop forms — where the condition is seen, and the minimum number of turns
- Table 33.2 — The three pieces of checking an invariant
- Table 33.3 — Four ways invariants are used in practice
- Table 33.4 — What an invariant catches
- Table 33.5 — Lifetime, by where the variable is declared
- Table 33.6 — What may go in
for’s first slot — by standard and compiler - Table 33.7 — When the condition slot touches the loop variable
- Table 33.8 — What compilers do with a loop that may not end
- Table 33.9 — The mistakes that appear once loops are nested
- Table 34.1 — The groups of operators at a glance
- Table 35.1 — Lvalue and rvalue — the relation the standard sets
- Table 35.2 — How many times the left side is evaluated in a compound assignment
- Table 35.3 — Assignment, case by case
- Table 35.4 — Assignment and side effects — what to remember
- Table 36.1 — What an object, an address and a pointer each are
- Table 36.2 — The same number means different things in different places
- Table 36.3 — The basic rules for handling a pointer
- Table 36.4 — Build options that catch pointer accidents
- Table 36.5 — Pointer sizes, by platform
- Table 36.6 — The specifiers that print a pointer
- Table 37.1 — Which spellings count as a null pointer constant
- Table 37.2 — The layers that handle null, and what each promises
- Table 37.3 — Where C and C++ part over null
- Table 38.1 — The privileges of
void *and the character pointers - Table 38.2 — Idioms that separate once the provenance model lands
- Table 39.1 — What follows from elements being flush against each other
- Table 39.2 — The four shapes of pointer arithmetic
- Table 39.3 — Which arithmetic a pointer may join, and which not
- Table 39.4 — What GCC says to the forbidden shapes
- Table 39.5 — The three types that hold an address as an integer
- Table 39.6 — How far pointer arithmetic is allowed
- Table 40.1 — How a multidimensional subscript unfolds
- Table 40.2 — The four patterns for handling multidimensional data
- Table 40.3 — Multidimensional arrays — what to remember
- Table 41.1 — The five axes that separate an array from a pointer
- Table 41.2 — The number of steps an indexed access takes
- Table 41.3 — What happens when the declarations disagree
- Table 41.4 — The three rules by which an array becomes a pointer
- Table 41.5 — The places decay does not happen
- Table 41.6 — In a parameter only the outer layer changes
- Table 41.7 — The same three words, two layouts
- Table 41.8 — One more level for each thing you mean to change
- Table 41.9 — The ways around returning an array
- Table 41.10 — Choosing between array and pointer for the job
- Table 41.11 — Arrays and pointers — what to remember
- Table 42.1 — Same sum, different order
- Table 42.2 — Devices for shedding several layers, by language
- Table 42.3 — Four ways out of nested loops
- Table 42.4 — The discipline for using
goto - Table 42.5 — Three shapes for a macro body
- Table 42.6 — Loop idioms and their traps
- Table 43.1 — The kinds of string literal and their sizes
- Table 44.1 — How each input function reports success, and where it trips
- Table 45.1 — The standard’s four axes — storage duration, scope, linkage, name space
- Table 45.2 — The four storage durations and their lifetimes
- Table 45.3 — The kinds of scope
- Table 45.4 — The three kinds of linkage
- Table 45.5 — The seven storage-class specifiers
- Table 45.6 — The three places two storage classes may be written together (C23)
- Table 45.7 — What lives in each region, and for how long
- Table 46.1 — What
callocpromises and what it does not - Table 46.2 — Two ways to spell a
malloccall - Table 46.3 — What the compiler says when it is called undeclared
- Table 46.4 — Mistakes around freeing, and the diagnostics
- Table 46.5 — What a C++ compiler says to the same code
- Table 47.1 — What
{ 0 }puts in, by member type - Table 47.2 — Which rule applies depends on what is being asked
- Table 47.3 — Three ways to move a struct with a flexible array member
- Table 48.1 — The two demands that create tail padding
- Table 48.2 — Three ways to pass a struct, and what each is worth
- Table 48.3 — What goes wrong when a struct is written out whole
- Table 48.4 — Anonymous members — shapes and meaning
- Table 48.5 — Where an anonymous member is forbidden
- Table 48.6 — Where
container_ofearns its keep - Table 48.7 — Using structs — what to remember
- Table 49.1 — Ways to type-pun, and how C rules on each
- Table 49.2 — Non-value representations — where they come from, what touching them does
- Table 49.3 — The size and alignment rules of a union
- Table 49.4 — What the implementation decides about bit-fields
- Table 49.5 — The bit layout of Johab Hangul
- Table 50.1 — What an expression carries
- Table 50.2 — Associativity, by operator group
- Table 50.3 — Where precedence groups it differently than intended
- Table 50.4 — Prefix and postfix increment, compared
- Table 50.5 — The standard’s sentences that set sequence points
- Table 50.6 — Results that differ by optimisation level
- Table 50.7 — How C and C++ rule on the same code
- Table 50.8 — The contract of the arithmetic operators
- Table 50.9 — The contract of the relational operators
- Table 50.10 — The contract of the logical operators
- Table 50.11 — The contract of the bitwise operators
- Table 50.12 — The contract of the assignment operators
- Table 50.13 — The contract of the member and subscript operators
- Table 50.14 — The contract of the remaining operators
- Table 50.15 — Verdicts on expressions seen often
- Table 50.16 — Where a constant expression is required
- Table 50.17 — The places left unspecified
- Table 50.18 — The places the implementation decides
- Table 50.19 — Things that look like expressions
- Table 50.20 — Expressions and operators — what to remember
- Table 51.1 — The letters used in the table below
- Table 51.2 — The five moves on a single bit
- Table 51.3 — Three masks
- Table 51.4 — The idioms one meets most often
- Table 51.5 — What
<stdbit.h>named (there areuc/us/ui/ul/ullvariants too) - Table 51.6 — Rules for working with bits
- Table 51.7 — Accidents around bit work
- Table 51.8 — What the compiler already knows — checked on this machine
- Table 51.9 — Where bit work actually appears
- Table 54.1 — Kinds of undefined behaviour and the standard’s stance
- Table 54.2 — What the standard requires, and what breaking it means
- Table 54.3 — Common UB code and where the standard puts it
- Table 54.4 — Two ways to write “control must not come here”
- Table 55.1 — The forms of
mainand their standing - Table 55.2 — The ways to end a program
- Table 55.3 — Exit status values and their meanings
- Table 55.4 — The three faces of
main— what to remember - Table 57.1 — The stages of a split build
- Table 57.2 — Output size and content, by build
- Table 57.3 — What an ABI settles
- Table 57.4 — Two ways to return a struct (x86-64 System V)
- Table 57.5 — The same 64-bit machine, a different promise
- Table 57.6 — Changes that are source compatible but not binary compatible
- Table 57.7 — The tables linking uses, and the shape of indirection
- Table 58.1 — The four scopes the standard defines
- Table 58.2 — Working discipline for shadowing
- Table 58.3 — Two layers make names, by two different rules
- Table 58.4 — Three questions about a name and its object
- Table 59.1 — The four name spaces and what lives in each
- Table 59.2 — The three axes that settle a name
- Table 59.3 — Naming policies and their grounds
- Table 59.4 — Options that catch shadowing, measured
- Table 59.5 — The range of reserved names
- Table 60.1 — When a name collision shows up
- Table 60.2 — Prefix conventions in real projects
- Table 60.3 — Handling symbol visibility, per platform
- Table 60.4 — What C++
namespacegains and costs - Table 60.5 — Symbol kinds by declaration, as
nmshows them - Table 60.6 — Naming conventions and their grounds
- Table 60.7 — The name in source and the name the linker sees
- Table 60.8 — Habits worth forming about names
- Table 61.1 — The rules for using a macro
- Table 61.2 — Translation phases — Korean names and the standard’s
- Table 61.3 — Translation phases 1-2 — what happens
- Table 61.4 — Translation phases 3-4 — what happens
- Table 61.5 — Translation phases 5-6 — what happens
- Table 61.6 — Translation phases 7-8 — what happens
- Table 61.7 — The eight translation phases at a glance
- Table 62.1 — One name in three places
- Table 62.2 — The operands of a call expression
- Table 62.3 — The rules around prototypes, before and after
- Table 62.4 — Adjustments applied to arguments and results
- Table 62.5 — One source, two orders — measured on this machine
- Table 62.6 — Sequencing rules around a call
- Table 62.7 — The five steps of one call
- Table 62.8 — Responsibility for preserving registers
- Table 62.9 — Four conventions from the desktop — as emitted by this machine’s compilers
- Table 62.10 — Three conventions on 32-bit Windows —
int f(int,int)built with this machine’s mingw - Table 62.11 — One line, six machines
- Table 62.12 — Handing over one structure — as the compilers emitted it
- Table 62.13 — Three ways of writing one thing
- Table 62.14 — Accidents around a call
- Table 63.1 — How values are promoted through a variadic call
- Table 63.2 — The ways a variadic call breaks
- Table 64.1 — Callback designs and their relation to the standard
- Table 64.2 — Round-tripping a generic function pointer
- Table 64.3 — Ways to print a function pointer, and their portability
- Table 64.4 — What may be done to a function pointer
- Table 64.5 — The rules for using a callback
- Table 65.1 — The vocabulary for reading a declaration
- Table 65.2 — Reading a declaration with
constin it - Table 65.3 — Reading a declaration through, step by step
- Table 65.4 — Reading a hard declaration through, step by step
- Table 65.5 — Reading declarations — what to remember
- Table 66.1 — The families of the standard library and their headers
- Table 66.2 — Output conversions, by data type
- Table 66.3 — Input conversions, by data type
- Table 67.1 — The standard headers at a glance
- Table 67.2 — Headers added by edition
- Table 67.3 — The terrain of the standard library — what to remember
- Table 68.1 — Success and failure in
<stdio.h>functions - Table 68.2 — The rules for handling a stream
- Table 69.1 — The reading functions and how they rate
- Table 69.2 — The writing functions and what to watch
- Table 69.3 — Choosing the I/O function that fits the job
- Table 70.1 — The string-copy functions — standing and truncation
- Table 70.2 — The string-search functions and what to watch
- Table 70.3 — Choosing the string function that fits the job
- Table 71.1 — The contracts and traps of
<stdlib.h> - Table 71.2 — What cleanup each way of ending performs
- Table 71.3 — The
<stdlib.h>function that fits the job - Table 72.1 — When each
<ctype.h>function answers true - Table 72.2 — The rules for using character classification
- Table 73.1 — What a locale changes — Korea and Germany
- Table 73.2 — Locale categories and the functions each governs
- Table 73.3 — What
setlocale’s second argument means - Table 73.4 — Locale names — their parts and what settles them
- Table 73.5 — The standards behind locale notation
- Table 73.6 — The precedence of the locale environment variables
- Table 73.7 — The steps of handling a locale
- Table 73.8 — Locales 1 — what to remember
- Table 74.1 — The members of
struct lconv - Table 74.2 — The grouping array’s values and meanings
- Table 74.3 — What the sign-position values mean
- Table 74.4 — Assembling a currency string, piece by piece
- Table 74.5 —
strftimeconversions — families and properties - Table 74.6 — Collation schemes and the means for each
- Table 74.7 — The locale tool that fits the job
- Table 74.8 — Locales 2 — what to remember
- Table 75.1 — What the standard settles about
wchar_t, and what it leaves - Table 75.2 — The macros around wide characters
- Table 75.3 — Wide character and string literals — types and encodings
- Table 75.4 — Which header each wide-character macro lives in
- Table 75.5 — The layers of multibyte conversion functions
- Table 75.6 — What
mbrtowc’s return values mean - Table 75.7 — Wide characters 1 — what to remember
- Table 76.1 — The de facto encoding, by platform
- Table 76.2 — The ranges of the surrogate area
- Table 76.3 — Windows API suffixes and their string types
- Table 76.4 — Why UTF-8 is the default choice
- Table 76.5 — String types, by toolkit
- Table 76.6 — Stream orientation — states and meanings
- Table 76.7 — Wide characters 2 — what to remember
- Table 77.1 — What to use, place by place
- Table 77.2 — The properties of UTF-8 and what they buy
- Table 77.3 — Byte sequences that must be rejected
- Table 77.4 — The layers of counting text and their units
- Table 77.5 — The four Unicode normalisation forms
- Table 77.6 — Where handling text slips
- Table 77.7 — Legacy encodings, by region
- Table 77.8 — Trail-byte ranges of the legacy encodings
- Table 77.9 — The means for handling Unicode
- Table 77.10 — Unicode in practice — what to remember
- Table 78.1 — The traps of
<math.h> - Table 78.2 — Choosing the maths function for the situation
- Table 79.1 — The types and functions of
<time.h> - Table 79.2 — The
strftimespecifiers - Table 79.3 — What C23 added to
<time.h> - Table 79.4 — The time function that fits the job
- Table 80.1 — The diagnostic and control functions
- Table 80.2 — The diagnostic tools and their rules
- Table 81.1 — The declarations of
<signal.h> - Table 81.2 — What a handler receives and what it means
- Table 81.3 — The standard signals and their default actions
- Table 81.4 — What is allowed inside a handler
- Table 81.5 — What blocks async-signal safety
- Table 81.6 — When a handler calls
malloc - Table 81.7 — Using signals together with
longjmp - Table 81.8 — The gaps in standard
signal, andsigaction - Table 81.9 — The members of
siginfo_t - Table 81.10 — What the
sigactionflags mean - Table 81.11 — The members that handle a signal set
- Table 81.12 — What each signal is used for
- Table 81.13 — Why it had to be a signal
- Table 81.14 — Signals — what to remember
- Table 82.1 — The declarations of
<setjmp.h> - Table 82.2 — What
setjmpreturns - Table 82.3 — The contexts where
setjmpis allowed - Table 82.4 —
longjmp’s conditions and what breaking them means - Table 82.5 — What the jump buffer stores
- Table 82.6 — The parts of a jump buffer and their sizes
- Table 82.7 — Variable values after a
longjmp - Table 82.8 — Which variables need
volatile - Table 82.9 — What
longjmpbreaks - Table 82.10 — Exception machinery in other languages
- Table 82.11 — Who solves resource cleanup
- Table 82.12 — The recommended approach, by intent
- Table 82.13 — Non-local jumps — what to remember
- Table 83.1 — What Annex K added, and where it stands today
- Table 83.2 — The headers that became optional
- Table 83.3 — What each edition added, and whether it is used
- Table 84.1 — The functions of
<threads.h> - Table 84.2 — What
shared += 1really does - Table 84.3 — Kinds of mutex and where each fits
- Table 84.4 — The mutex functions
- Table 84.5 — The condition-variable functions
- Table 84.6 — Shapes of once-only initialisation
- Table 84.7 — The thread-specific storage functions
- Table 84.8 — Why C11 threads are used less
- Table 84.9 — C11, POSIX and Win32 thread APIs compared
- Table 84.10 — Thread recommendations, by situation
- Table 85.1 — The three things an atomic operation gives
- Table 85.2 — The atomic operations and where each fits
- Table 85.3 — CAS is realised differently from machine to machine
- Table 85.4 — The same code pays a different price per machine — raising the flag
- Table 85.5 — The memory orders and what each guarantees
- Table 85.6 — The concurrency tool recommended, by situation
- Table 85.7 — Atomics — what to remember
- Table 86.1 — Checking overflow — the old idiom and today’s
- Table 86.2 — Asking about overflow — what to remember
- Table 87.1 — The names that went from macro to keyword
- Table 87.2 — The words C23 brought in
- Table 87.3 — The seven standard attributes
- Table 87.4 — From macro to keyword — what to remember
- Table 88.1 — The sections of an executable and their permissions
- Table 88.2 — Address-space layout in Linux and Windows
- Table 88.3 — Memory layout on embedded machines
- Table 88.4 — A program’s memory layout — what to remember
- Table 89.1 — The layers of an allocator
- Table 89.2 — Ways to ease fragmentation
- Table 89.3 — Alternative allocators and their character
- Table 89.4 — Alternative standard library implementations
- Table 89.5 — Inside the allocator — what to remember
- Table 90.1 — The five bugs — what C gives and what is needed
- Table 91.1 — What proven does not do
- Table 91.2 — proven’s name shapes and what they mean
- Table 91.3 — Bringing proven into a build
- Table 92.1 — Accidents born of an ignored error
- Table 92.2 — The result package types
- Table 92.3 — Error handling, case by case
- Table 93.1 — Ownership and writability of the view types
- Table 93.2 — What the checked arithmetic functions return
- Table 93.3 — The names of the byte operations
- Table 93.4 — Alignment functions and their contracts
- Table 94.1 — The steps of an allocation
- Table 94.2 — Where each allocator function fits
- Table 94.3 — Heap, arena and pool compared
- Table 94.4 — Choosing the allocator for the situation
- Table 95.1 — Allocation and destruction in the string functions
- Table 95.2 — Failure atomicity in the string operations
- Table 95.3 — The contracts of the UTF-8 functions
- Table 95.4 — Failure and ownership in the text functions
- Table 96.1 — What may go in a formatting slot
- Table 96.2 — The formatting functions and their allocators
- Table 96.3 — What the parsing functions read and return
- Table 96.4 — The scanner API
- Table 97.1 — Containers — creating, allocating, iterating
- Table 97.2 — The container macros
- Table 97.3 — Keys for a hash map, and what to watch
- Table 97.4 — The algorithm tools and where each fits
- Table 98.1 — The steps of handling a file
- Table 98.2 — What the file flags mean
- Table 98.3 — The stream functions and what to watch
- Table 98.4 — The time and random APIs
- Table 99.1 — Coroutines — what is verified and what is not
- Table 99.2 — The answers to the five bugs, and their chapters
- Table 100.1 — The tiny JSON — what is in and what is out
- Table 100.2 — What the code says and what it leaves unsaid
- Table 100.3 — The same place in plain C and in proven
- Table 100.4 — What each tool did, and what without it
- Table 100.5 — Writing it three times — what to remember
- Table 101.1 — The tools of practice
- Table 101.2 — What each profiler measures
- Table 101.3 — Notable C projects, and why C
- Table 101.4 — The road MISRA C has travelled
- Table 101.5 — What the safety levels mean
- Table 101.6 — The coding standards and what each governs
- Table 101.7 — What the standards forbid, and where this book treats it
- Table 101.8 — What C and C++ each lack of the other
- Table 102.1 — The jobs a build takes on
- Table 102.2 — What belongs in a header and what does not
- Table 102.3 — Common folder kinds and their reasons
- Table 102.4 — Kinds of test and what each catches
- Table 102.5 — What to hand the machine and what people look at
- Table 102.6 — Which document answers which question
- Table 102.7 — Build and test — what to remember
- Table 103.1 — The words of this chapter
- Table 103.2 — What was a fixture in the golden demonstration
- Table 103.3 — What must not be made a fixture
- Table 103.4 — What a negative check reveals
- Table 103.5 — With a ratchet and without
- Table 103.6 — An example of dividing the depth
- Table 103.7 — The steps one piece of work passes
- Table 103.8 — The faces of silent failure
- Table 103.9 — How the work turns — what to remember
- Table 104.1 — Embedded compilers and the chips they target
- Table 104.2 — Embedded tools, by job
- Table 105.1 — What C23 brought, and where we met it
- Table 105.1 — Associativity, by operator group
- Table 105.2 — Where precedence groups it differently than intended
- Table 105.3 — Where to look for what
- Table 105.1 — The skeleton of output and input conversions
- Table 105.2 — The full list of output conversions
- Table 105.3 — The places of flags, width and precision
- Table 105.4 — The length modifiers
- Table 105.5 — The full list of input conversions
- Table 105.6 — The return values of the formatted I/O functions
- Table 105.7 — Common formatting mistakes and their fixes
- Table 105.1 — The risk of each conversion
- Table 105.1 — Where to get the standard documents
- Table 105.2 — Books to read next
- Table 105.3 — Talks worth watching, and the chapters they meet
- Table 105.4 — The tools’ character and what they give a learner
- Table 105.5 — Reference material
- Table 105.6 — The marks of outdated code
- Table 105.7 — The standard editions and their free drafts
- Table 105.1 — EBNF notation and its meaning
- Table 105.2 — The conventions for writing the grammar
- Table 105.3 — What the grammar settles, and what lies outside
- Table 105.4 — The grammar — what to remember
- Table 105.1 — What the columns of this reference mean
- Table 105.2 —
<string.h>reference — memory blocks (mem*) - Table 105.3 —
<string.h>reference - Table 105.4 —
<string.h>reference — comparing and length - Table 105.5 —
<string.h>reference — searching and splitting - Table 105.6 —
<string.h>reference — error strings - Table 105.7 — Macros and types
- Table 105.8 — What holds for every function
- Table 105.9 —
<ctype.h>reference - Table 105.10 — Reference for the remaining headers
- Table 105.11 — The common conventions of this reference
- Table 105.12 —
<assert.h>entry by entry - Table 105.13 —
<errno.h>entry by entry - Table 105.14 —
<setjmp.h>entry by entry - Table 105.15 —
<stdarg.h>entry by entry - Table 105.16 —
<stddef.h>entry by entry - Table 105.17 — How they came to be empty
- Table 105.18 — The eleven names
<iso646.h>gives - Table 105.19 — How to read the names
- Table 105.20 —
<limits.h>entry by entry - Table 105.21 — The three that belong to no type
- Table 105.22 — What each suffix means — all three prefixes take them
- Table 105.23 — The names that belong to no type
- Table 105.24 — Three families — what each promises
- Table 105.25 —
<stdint.h>entry by entry - Table 105.26 — Limits belonging to types from other headers
- Table 105.27 —
<inttypes.h>entry by entry - Table 105.28 — How to read the format macros
- Table 105.29 —
<stdbit.h>entry by entry — written with the type-generic names - Table 105.30 —
<locale.h>entry by entry - Table 105.31 —
<wctype.h>entry by entry - Table 105.32 —
<uchar.h>entry by entry - Table 105.33 —
<signal.h>entry by entry - Table 105.34 — Exception flags and rounding directions
- Table 105.35 —
<fenv.h>entry by entry - Table 105.36 — What it picks
- Table 105.37 — The ones that take a value apart
- Table 105.38 — Those that pair with
<math.h> - Table 105.39 — Making values and choosing the arithmetic
- Table 105.40 — Threads themselves —
thrd_ - Table 105.41 — Getting along —
mtx_,cnd_,call_once - Table 105.42 — Thread-specific storage, and the types
- Table 105.43 — The operations of
<stdatomic.h> - Table 105.44 — The type names —
atomic_in front - Table 105.45 — Strings and memory — the
<string.h>counterparts - Table 105.46 — Conversion — between bytes and wide, and to numbers
- Table 105.47 — Input and output — the
<stdio.h>counterparts - Table 105.48 — Types, macros and Annex K
- Table 105.49 —
<time.h>reference - Table 105.50 — Types and macros
- Table 105.51 —
<stdlib.h>reference — memory allocation - Table 105.52 —
<stdlib.h>reference — ending the program - Table 105.53 —
<stdlib.h>reference — between strings and numbers - Table 105.54 —
<stdlib.h>reference — arithmetic, sorting, randomness, multibyte - Table 105.55 — Annex K’s constraint handler
- Table 105.56 —
<stdio.h>reference — opening, closing, buffering - Table 105.57 —
<stdio.h>reference — reading and writing - Table 105.58 —
<stdio.h>reference — position and state - Table 105.59 — Macros, types and Annex K
- Table 105.60 — How to read the names
- Table 105.61 — Asking what a value is — these are macros
- Table 105.62 — The elementary functions
- Table 105.63 — Rounding, remainders, moving the exponent
- Table 105.64 — Keeping precision — computed wide, rounded once
- Table 105.65 — Decimal floating point only
- Table 105.1 — What C23 added to the language
- Table 105.2 — What C23 added to the preprocessor
- Table 105.3 — What C23 added to the library
- Table 105.1 — What standard C does not have
- Table 105.2 — What can be finished with standard C alone
- Table 105.3 — Between what and what does the gap lie
- Table 105.4 — The roads that lead on from C
- Table 105.5 — Roads to opening a window in C
- Table 105.6 — Things worth building to the end
- Table 105.7 — Places to see more C
- Table 105.8 — Courses and curricula
- Table 105.9 — Places to survey what exists
- Table 105.1 — What a dump holds and what it does not
- Table 105.2 — Program headers of a core file
- Table 105.3 — Three layers that turn an address into a name
- Table 105.4 — Common reasons no dump is left
- Table 105.1 — Four things an executable format must answer
- Table 105.2 — Three things to know about PE
- Table 105.3 — Formats told apart by their first few bytes
- Table 105.1 — What the operating system did, and who does it without one
- Table 105.2 — Interrupt, exception, trap — the axes that separate them
- Table 105.3 — When an interrupt arrives, who saves what
- Table 105.4 — Touching the same address — as memory, and as a device
- Table 105.5 — Two designs for reaching a device
- Table 105.6 — Classic port addresses met verbatim in old code
- Table 105.7 — What
volatilegives and what it does not - Table 105.8 — Three reasons embedded work decides against
malloc - Table 105.9 — Earlier chapters, read again after the visit
- Table 105.1 — What the firmware does
- Table 105.2 — How the MBR’s 512 bytes divide up
- Table 105.3 — The BIOS way and the UEFI way
- Table 105.4 — Bootloaders commonly met
- Table 105.5 — GRUB’s stages (the old BIOS way)
- Table 105.6 — Where
core.imglives - Table 105.7 — The order in which UEFI firmware looks for the next thing
- Table 105.8 — How Linux starts with secure boot enabled
- Table 105.9 — The stages of the U-Boot family
- Table 105.10 — How MCUboot makes an update safe
- Table 105.11 — What passes across at each change of stage
- Table 105.12 — Symptom → which link of the chain
- Table 105.13 — The Windows boot chain
- Table 105.1 — The words used in this appendix
- Table 105.2 — Four axes that separate connections
- Table 105.3 — The connections covered in this appendix
- Table 105.4 — The ten bits of an 8N1 frame
- Table 105.5 — How to read a notation like
8N1 - Table 105.6 — TTL-level UART and RS-232
- Table 105.7 — The signals of RS-232 (on a 9-pin connector)
- Table 105.8 — Two kinds of flow control
- Table 105.9 — Errors met in a UART’s status register
- Table 105.10 — The signals of a parallel (Centronics) port
- Table 105.11 — Why parallel loses as things get faster
- Table 105.12 — The signals and markers of I2C
- Table 105.13 — I2C speed modes
- Table 105.14 — The four wires of SPI
- Table 105.15 — SPI’s four modes
- Table 105.16 — I2C against SPI
- Table 105.17 — Two unusual schemes
- Table 105.18 — PCI and PCI Express
- Table 105.19 — PCIe generations and effective speed (per lane)
- Table 105.20 — The main fields of PCI configuration space (header type 0)
- Table 105.21 — The low bits of a BAR say what kind it is
- Table 105.22 — USB speed grades
- Table 105.23 — USB’s four transfer types
- Table 105.24 — Edge triggering and level triggering
- Table 105.25 — How interrupt delivery changed
- Table 105.26 — How DMA uses the bus
- Table 105.27 — Three things that catch you with DMA
- Table 105.28 — The three at a glance
- Table 105.1 — The words used in this appendix
- Table 105.2 — Three kinds of sector size
- Table 105.3 — The whole layout of the MBR’s 512 bytes
- Table 105.4 — The 16 bytes of an MBR partition entry
- Table 105.5 — Bit layout of the three CHS bytes
- Table 105.6 — Partition type bytes commonly seen
- Table 105.7 — The two EBR entries — their bases differ
- Table 105.8 — MBR and GPT
- Table 105.9 — Every field of the GPT header (LBA 1, 92 bytes)
- Table 105.10 — Every field of a GPT partition entry (128 bytes)
- Table 105.11 — GPT attribute bits worth knowing
- Table 105.12 — The five groups of a GUID and their storage order
- Table 105.13 — Type GUIDs commonly seen
- Table 105.14 — What 1 MiB alignment lines up with
- Table 105.15 — Where a filesystem’s self-description lives
- Table 105.16 — The main fields of the FAT32 boot sector (BPB)
- Table 105.17 — FAT32 entry values (only the low 28 bits are used)
- Table 105.18 — The main fields of the ext4 superblock (start of partition + 1024 bytes)
- Table 105.19 — The main fields of the NTFS boot sector
- Table 105.20 — Filesystems commonly met
- Table 105.21 — The time for one read on a hard disk
- Table 105.22 — Three units inside an SSD
- Table 105.23 — What “it cannot be overwritten” produces
- Table 105.24 — The lower rungs of the ladder (measured on this machine)
- Table 105.25 — Design guidance that comes from this layer
- Table 105.26 — Symptom → which layer was damaged
- Table 105.1 — The clocks met in C and POSIX
- Table 105.2 — The numbers of the machine this was written on, and of an ARM phone (as the example read them)
- Table 105.3 — What to measure how — the method depends on the size
- Table 105.4 — Which representative value to use
- Table 105.5 — Six disciplines for measuring
- Table 105.6 — What each rung does
- Table 105.7 — What pointer chasing achieves
- Table 105.8 — Design guidance from this measurement
- Table 105.9 — Four consequences of moving in lines
- Table 105.10 — The same computation, laid out differently
- Table 105.11 — How to choose a layout
- Table 105.12 — The three cases of address translation
- Table 105.13 — Cost per access against page count (measured on this machine and an ARM phone)
- Table 105.14 — Where the first-touch cost actually bites
- Table 105.15 — The same source, different code — time per element (measured here)
- Table 105.16 — Cost by pattern (in the version that kept a real branch)
- Table 105.17 — Guidance from this measurement
- Table 105.18 — How cores treat a cache line (roughly)
- Table 105.19 — Two threads each incrementing their own slot (measured here and on an ARM phone)
- Table 105.20 — How to avoid false sharing
- Table 105.21 — The cost of sharing (measured here and on an ARM phone)
- Table 105.22 — Changing only the magnitude of the values (measured here)
- Table 105.23 —
floatanddouble— with and without vector instructions - Table 105.24 — Cost by operation (data inside L1, measured here)
- Table 105.25 — Techniques that follow from this measurement
- Table 105.26 — The measurements of this appendix (this machine and an ARM phone, medians)
- Table 105.27 — The latency curve of an ARM phone (random access, pinned to the performance cores)
- Table 105.28 — Symptom → where to suspect first
- Table 105.1 — Three ways to govern memory
- Table 105.2 — Page-table levels and page sizes — the two RISC-V schemes
- Table 105.3 — What changes on a machine without translation
- Table 105.4 — Machines with more than one address space
- Table 105.5 — When DMA and the cache disagree
- Table 105.1 — The order in which sources are written
Figures#
- Figure 3.1 — A cell of memory — eight bits each, numbered one by one
- Figure 3.2 — Big-endian — the most significant byte goes first
- Figure 3.3 — Little-endian — the least significant byte goes first
- Figure 4.1 — Four aligned bytes — starting at a multiple of four
- Figure 5.1 — The memory layout of one program. Nearly every later chapter is read on top of this picture.
- Figure 6.1 — Outside, the value read as an
unsigned char; inside, the same bits read as asigned char. - Figure 6.2 — The same eight bits: what fills the front depends on the signedness of the original type.
- Figure 7.1 — The bit layout of
floatanddouble. The width of each field is the ratio of its bit count. - Figure 12.1 — Virtual pages are paired with physical ones through the page table. What was contiguous is scattered — that one fact is what this figure carries.
- Figure 18.1 — How a screen that shows one source line becoming several machine-code lines is laid out.
- Figure 18.2 — Values as boxes, pointers as arrows — the picture a visualiser draws.
- Figure 27.1 — How the standard divides types. A dashed box is a name that gathers several branches.
- Figure 30.1 — Follow the four in order. Most accidents happen at step 3.
- Figure 36.1 — The three things that travel with one pointer value. The same address does not make the same pointer.
- Figure 39.1 — The address is the same and the type is not — so how many elements there are disappears.
- Figure 39.2 — The distance
+1jumps is the size of the type pointed at. - Figure 40.1 — The two jumps that reach
a[2][1]— one row-sized, one element-sized. - Figure 41.1 — An array of pointers — the array itself is contiguous, what it points at is scattered.
- Figure 41.2 — To change the caller’s pointer you must pass the place where that pointer lives.
- Figure 47.1 — The hatched cells are padding. Each member sits at a multiple of its alignment, and space is added at the end too.
- Figure 47.2 — Header and data in one block — two allocations become one.
- Figure 47.3 — Same leading members; the last member’s type moves where the array begins.
- Figure 48.1 — An array of structs — since no gap is allowed between elements, the size is rounded up to a multiple of the alignment.
- Figure 48.2 — Above, twelve bytes with the padding going out; below, seven bytes in the order we chose.
- Figure 85.1 — If the flag is visible, is the data written before it visible too?
- Figure 105.1 — The formats differ; the loader’s questions do not.
- Figure 105.1 — How a hardware exception reaches my C function, and why it cannot go back.
- Figure 105.2 — How much the hardware saves differs by chip — and that difference settles the compiler’s work.
- Figure 105.3 — A design with one address space and a design with two.
- Figure 105.1 — The chain of booting — the machines differ; the work of each link does not.
- Figure 105.1 — Sending the same byte serially and in parallel.
- Figure 105.2 — The path where the CPU carries the data, and the path where DMA does.
- Figure 105.1 — Three layers on one disk — the row of sectors, the partition table, the filesystem.
- Figure 105.2 — The EBR chain — two entries of one table with different bases.
- Figure 105.3 — An SSD’s pages and blocks — where write amplification comes from.
- Figure 105.1 — Three traps in measuring, and the guard against each.
- Figure 105.2 — The latency curve, actually measured. The vertical dashed lines are this machine’s cache boundaries.
- Figure 105.3 — Cost per access against stride. The vertical dashed line is this machine’s cache line size.
- Figure 105.4 — What happens in the pipeline when the prediction is right and when it is wrong.
- Figure 105.5 — Sharing a line, and kept apart.