Appendix F — What C23 added, and where this book covers it
Every edition of the standard records “what changed” about itself (C23′s annex M.2). Taking that list as the frame, this appendix gathers where in this book each item is covered. It is a place for someone who already knows the new standard to ask “which chapter tells that story”, and equally for someone who has finished the book to check “did I meet all of C23”.
★ This book does not teach C23 separately. Rather than teaching the old way first and appending the new, it explains in C23 from the start and adds “it used to be like this” only where that helps. So the items below do not sit together; they are scattered through their own subjects. The three tables below stitch those places back together.
The language#
| What | In brief | Where |
|---|---|---|
bool, true, false and others promoted to keywords | what were macros became keywords | chapter 97 |
nullptr and nullptr_t | a null constant with a type of its own | chapters 37 and 97 |
constexpr | an object whose value is fixed at translation time | chapters 21 and 97 |
typeof, typeof_unqual | write down an expression’s type verbatim | chapter 97 |
auto type inference | the type is drawn from the initialiser | chapter 97 |
attributes [[…]] | write intent no type can hold (seven of them) | chapter 97 |
_BitInt(N) | an integer whose width you choose | chapters 21 and 28 |
| two’s complement settled, old sign forms removed | integer representation pinned to one | chapters 6 and 28 |
| limits redefined in terms of width | the negative end of the guaranteed range moved | chapter 28 |
binary literals 0b | write bits as bits | chapters 21 and 53 |
digit separator ' | 1'000'000 reads in groups | chapter 21 |
empty initialiser {} | initialisation that zeroes the padding too | chapter 47 |
| storage class on compound literals | their lifetime can be changed | chapter 48 |
| fixed underlying type for enums | enum E : unsigned { … } | chapter 27 |
| relaxed tag compatibility | same-tag, same-content structs are compatible within one translation unit too | chapter 47 |
| labels in more places | before declarations and at a block’s end | chapter 32 |
| K&R identifier-list definitions removed | the old definition syntax is gone | chapter 66 |
f() = f(void) | empty parentheses now mean no parameters | chapter 66 |
| parameter names may be omitted | even in a definition | chapter 66 |
va_start needs no second argument | ... may stand with no parameter before it | chapter 67 |
| variably modified types mandated | VLAs themselves stay optional | chapter 40 |
| Unicode identifiers | which characters may appear in a name is settled | chapter 8 |
@, $ and the grave accent (U+0060) added to the character set | more characters may appear in source | chapter 8 |
u8 character constants | the string prefix now works on characters | chapter 21 |
u8, u, U encodings pinned | settled as UTF-8, UTF-16, UTF-32 | chapters 8 and 85 |
| literal encodings separated | split apart from the execution character set | chapter 8 |
| wide/narrow literal concatenation removed | mixing them is gone | chapter 43 |
| potentially reserved identifiers | a middle level between reserved and not | chapter 63 |
ptrdiff_t minimum width 16 | the requirement fell from 17 | chapter 27 |
| width exception for extended integer types | allows things like int128_t | chapter 28 |
Table 115.1 — What C23 changed in the language
The preprocessor#
| What | In brief | Where |
|---|---|---|
#embed | bring binary data into the source as it is | chapter 65 |
__VA_OPT__ | handles the empty variadic case | chapter 65 |
__has_include | asks whether a header is there | chapters 53 and 96 |
#elifdef, #elifndef | the short form of #elif defined | chapter 65 |
#warning | says something without failing | chapter 65 |
one-argument static_assert | the message may be left out | chapter 90 |
Table 115.2 — What C23 added to the preprocessor
The library#
| What | In brief | Where |
|---|---|---|
<stdbit.h> | counting and rotating bits became standard functions | chapters 53 and 93 |
<stdckdint.h> | arithmetic that reports overflow as a value | chapters 56 and 96 |
unreachable | promises that control never comes here | chapter 56 |
memset_explicit | an erase the optimiser may not remove | chapter 80 |
memalignment | asks a pointer for its alignment | chapter 77 |
| qualifier-preserving search functions | put in a const, get a const back | chapter 80 |
free_sized, free_aligned_sized | tell the allocator the size you know | chapter 99 |
realloc(p, 0) is UB (undefined behavior) | an old grey zone moved outside the contract | chapter 46 |
several time bases, timespec_getres | a monotonic clock, and asking its resolution | chapter 89 |
timegm | the UTC counterpart of mktime | chapter 89 |
mbrtoc8, c8rtomb | the UTF-8 pair <uchar.h> was missing | chapter 85 |
call_once mandated | no longer optional | chapter 94 |
POSIX functions folded in (strdup and others) | common practice became standard | chapters 79–80 |
length modifiers for intN_t | printf and scanf know the fixed-width types | chapter 76 |
binary integer I/O %b | prints and reads 0b | chapter 53 |
| per-header version test macros | a header states what it has | chapter 19 |
DECIMAL_DIG obsolescent | the per-type macros take over | chapter 28 |
_Imaginary_I qualifiers adjusted | a small repair in an optional header | chapter 93 |
| harmonised with IEC 60559 | follows the floating-point standard more closely | chapter 54 |
| effective-type rules made precise | the ground of aliasing grew clearer | chapter 40 |
Table 115.3 — What C23 changed in the library
How to use these tables#
- To skim only what is new — follow the “Where” column of the three tables above and you have gone once around C23.
- To check your compiler keeps up — read chapter 19′s edition table together with
__STDC_VERSION__and the per-header version macros. ★ Being in the standard is not being in the compiler — chapter 97 measures two compilers ignoring[[unsequenced]]. - To move old code over — the last section of chapter 97 sets out an order.