Proven C Book←↑→

Appendix F — The standard library, entry by entry

This appendix is something to look things up in. Where the body dealt with “why”, this gathers “what and how” in one place. It follows Annex B of C23 (N3220), aiming to list every function, macro and type of every header without omission.

★ What is here is all of it. All thirty-one standard headers of Annex B of C23 (N3220) are covered — and that not one function, macro or type is missing is checked by machine on every build.

How to read it.

ColumnWhat is in it
NameThe function’s name. Where f/l variants exist they share one cell
FormThe declaration as the standard writes it. QChar and QVoid are the standard’s notation (C23) for a return that preserves qualifiers — hand in a const pointer and you get one back
Arguments and returnWhat each parameter is, what comes back, and how failure is reported
What it does · ★trapsA one-line summary. ★ marks a trap this book treats in the body

Table 105.1 — What the columns of this reference mean

Three things to say in advance.

First, the Annex K functions (those ending in _s) are included. They are in the standard but optional, and were never widely implemented — that story is in chapter 83. They are marked ★K here.

Second, an empty “trap” cell is written as “none”. Left blank, it could not be told apart from not yet examined.

Third, this appendix is not a transcription of the standard. The declarations are facts and stand as they are, but the explanations are this book’s own, and whatever could be measured was measured.

<string.h> — strings and memory#

Body: chapter 70 (close reading), chapter 43 (what a string is), chapter 44 (safe input).

This header mixes functions that take a size with functions that do not. That division is also the division between accidents.

Working on blocks of memory (mem*)#

NameFormArguments and returnWhat it does · ★traps
memcpyvoid *memcpy(void *restrict s1, const void *restrict s2, size_t n)s1 destination, s2 source, n bytes. Returns s1Moves n bytes. ★ If the regions overlap it is outside the contract — that is what restrict promises. If they may overlap, use memmove
memmovevoid *memmove(void *s1, const void *s2, size_t n)The same. Returns s1Moves correctly even when overlapping. No trap — if in doubt, use this
memcmpint memcmp(const void *s1, const void *s2, size_t n)Two regions and a length. Returns negative, 0 or positiveCompares bytes in order. ★ Do not compare whole structs — padding gets into the value (chapter 48)
memchrQVoid *memchr(QVoid *s, int c, size_t n)c is converted to unsigned char. Null if not foundSearches forward within n bytes. Unlike the string functions it does not stop at a NUL
memsetvoid *memset(void *s, int c, size_t n)c converted to unsigned char. Returns sFills n bytes with one value. ★ Not a way to make pointers null — all-bits-zero and the null representation are separate things (chapter 37)
memset_explicitvoid *memset_explicit(void *s, int c, size_t n)As memsetC23. A wipe the optimizer may not remove — for clearing a password just before freeing
memccpyvoid *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n)Copies up to and including c and returns the address after it; null if c was not metArrived in C23 (an old POSIX function). Does “copy up to the delimiter” in one step
memcpy_serrno_t memcpy_s(void *restrict s1, rsize_t s1max, const void *restrict s2, rsize_t n)Also takes the destination size s1max. 0 on success★K Annex K. On overflow it zeroes the destination and reports an error. Not widely implemented (chapter 83)
memmove_serrno_t memmove_s(void *s1, rsize_t s1max, const void *s2, rsize_t n)The same★K The same story
memset_serrno_t memset_s(void *s, rsize_t smax, int c, rsize_t n)The same★K The same story. memset_explicit is C23′s answer

Table 105.2 — <string.h> reference — memory blocks (mem*)

Copying and joining (strcpy and strcat families)#

NameFormArguments and returnWhat it does · ★traps
strcpychar *strcpy(char *restrict s1, const char *restrict s2)Returns s1Copies through the NUL. ★ It does not know the destination’s size — the classic overflow
strncpychar *strncpy(char *restrict s1, const char *restrict s2, size_t n)n is how many bytes to write, not the destination’s size★★ Despite the name it is not a safe function. On an exact fit it writes no NUL; when short it fills the remainder with zeros (slow). Chapter 70
strcatchar *strcat(char *restrict s1, const char *restrict s2)Returns s1Appends. ★ It does not know the size, and it finds the end again every time — repeated in a loop it becomes quadratic
strncatchar *strncat(char *restrict s1, const char *restrict s2, size_t n)n is at most how many bytes to append; the NUL goes on top of that★ So the buffer must hold n + 1 — the arithmetic differs from strncpy
strdupchar *strdup(const char *s)Null on failureArrived in C23. You must free it — ownership comes to you (chapter 94)
strndupchar *strndup(const char *s, size_t n)At most n bytes. Null on failureC23. Stops at n even if no end is found
strcpy_serrno_t strcpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2)0 on success★K Chapter 83
strncpy_serrno_t strncpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n)0 on success★K Chapter 83
strcat_serrno_t strcat_s(char *restrict s1, rsize_t s1max, const char *restrict s2)0 on success★K Chapter 83
strncat_serrno_t strncat_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n)0 on success★K Chapter 83

Table 105.3 — <string.h> reference

Comparing, and length#

NameFormArguments and returnWhat it does · ★traps
strlensize_t strlen(const char *s)Bytes, not counting the NUL★ Bytes, not characters (chapters 43 and 77). And it is O(n), so it does not belong in a loop condition (chapter 42)
strcmpint strcmp(const char *s1, const char *s2)Negative, 0 or positive★ Not “dictionary order” but order by unsigned char value. Human ordering is strcoll
strncmpint strncmp(const char *s1, const char *s2, size_t n)The sameCompares the first n bytes. Used for prefix tests
strcollint strcoll(const char *s1, const char *s2)The sameCompares in the order the locale prescribes (chapter 74). Slow — for repeated comparison use strxfrm
strxfrmsize_t strxfrm(char *restrict s1, const char *restrict s2, size_t n)Returns the length needed (excluding the NUL). If that is n or more, the contents of s1 are unspecifiedFreezes a locale comparison into a “key”. Keys can then be compared with strcmp
strnlen_ssize_t strnlen_s(const char *s, size_t maxsize)At most maxsize; 0 if s is null★K Yet this one is broadly useful — it measures a buffer that may have no end

Table 105.4 — <string.h> reference — comparing and length

Searching and splitting#

NameFormArguments and returnWhat it does · ★traps
strchrQChar *strchr(QChar *s, int c)Null if not found. If c is '\0' it points at the terminating NULFinds one byte, searching forward. ★ In a multibyte encoding it can land inside a character (chapter 77)
strrchrQChar *strrchr(QChar *s, int c)The sameSearches backward. Used to find the last separator in a path — ★ with the same danger
strstrQChar *strstr(QChar *s1, const char *s2)Null if not found; s1 if s2 is emptyFinds a substring. The standard prescribes no algorithm — it may be O(nm) in the worst case
strspnsize_t strspn(const char *s1, const char *s2)A lengthHow long the prefix made only of characters from s2 is. Used for skipping
strcspnsize_t strcspn(const char *s1, const char *s2)A lengthThe reverse — how far until a character from s2 appears
strpbrkQChar *strpbrk(QChar *s1, const char *s2)Null if not foundThe first place any character of s2 occurs
strtokchar *strtok(char *restrict s1, const char *restrict s2)The string on the first call, null thereafter. Null when there are no more★★ It destroys the original (writing NULs over the delimiters), and it hides state inside the function — not reentrant, not thread-safe. Chapter 70
strtok_schar *strtok_s(char *restrict s1, rsize_t *restrict s1max, const char *restrict s2, char **restrict ptr)Keeps the state outside, in ptr★K Moving the state out is the right direction. POSIX’s strtok_r had the same idea

Table 105.5 — <string.h> reference — searching and splitting

Error strings#

NameFormArguments and returnWhat it does · ★traps
strerrorchar *strerror(int errnum)The string for an error number★ May return a static buffer — a later call can overwrite it, and thread safety is not guaranteed (chapter 80)
strerrorlen_ssize_t strerrorlen_s(errno_t errnum)The length needed★K Pairs with strerror_s

Table 105.6 — <string.h> reference — error strings

Macro or typeWhat it isNote
NULLThe null pointer constantFrom C23 there is nullptr (chapters 37 and 87)
size_tThe unsigned type of sizes and countsIts home is <stddef.h> (chapter 36)
rsize_t★K Annex K’s size typeBounded by RSIZE_MAX
errno_t★K Annex K’s error typeEffectively int

Table 105.7 — Macros and types

<ctype.h> — the kinds of a single byte#

Body: chapter 72 (close reading), chapter 8 (the history of character sets).

All fourteen functions have the same shape — they take an int and return an int. ★ In that one line lies the trap that governs the whole header.

Common to every functionWhat it is
ArgumentA value representable as unsigned char, or EOF. ★ Anything else is outside the contract
★ The commonest accidentPassing a char directly. On a machine where char is signed, a byte of 128 or more becomes negative and leaves the contract. Always isalpha((unsigned char)c)
ReturnThe classifying functions return “nonzero if true”, 0 if false. Do not assume 1
LocaleAll but isdigit and isxdigit can be changed by LC_CTYPE (chapter 73)

Table 105.8 — What holds for every function

NameTrue forNote · ★traps
isalnumA letter or a digitisalpha or isdigit
isalphaA letter★ Not “A–Z, a–z” — the locale and the character set decide (chapter 8′s EBCDIC)
isblankA word separator — space and horizontal tabC99. Means “blank within a line”
iscntrlA control characterNot drawn on screen
isdigit0–9★ Independent of the locale — the standard fixes these ten
isgraphA printing character other than spaceisprint minus the space
islowerA lowercase letterThe locale decides
isprintA printing character, space included
ispunctA printing character that is neither letter, digit nor space
isspaceWhitespace — space, \\n, \\t, \\v, \\f, \\rUsed for skipping input
isupperAn uppercase letterThe locale decides
isxdigitA hexadecimal digit★ Independent of the locale
tolowerReturns the lowercase if it is an uppercase letter, otherwise the argument★ One character to one character. Turkish I and German ß break that assumption (chapter 77)
toupperThe reverse★ The same

Table 105.9 — <ctype.h> reference

<stdckdint.h> — arithmetic that answers about overflow#

Body: chapter 86 (close reading), chapter 28 (integers are finite), chapter 54 (undefined behaviour).

A header C23 brought in. All three are type-generic macros, not functions — which is why the forms say type1 and type2.

NameFormArguments and returnWhat it does · ★traps
ckd_addbool ckd_add(type1 *result, type2 a, type3 b)Writes the result into result. Returns true if it overflowed, false otherwise★ Mind the direction of the return — true is not “success” but “it overflowed”
ckd_subbool ckd_sub(type1 *result, type2 a, type3 b)The sameSubtraction. Also catches going below 0 in an unsigned type
ckd_mulbool ckd_mul(type1 *result, type2 a, type3 b)The sameMultiplication. ★ The most useful of the three for allocation arithmetic — overflow in n * sizeof *p is a classic security bug

Table 105.10 — Reference for the remaining headers

Common contractWhat it saysNote
Accuracy of the resultIf it did not overflow, the mathematically correct valueNot “the wrapped value”
When it overflowedresult receives the wrapped valueNot undefined behaviour — the value is settled
OperandsInteger types other than bool and the bit-precise integerschar is allowed too
Feature test__STDC_VERSION_STDCKDINT_H__Check for it and branch

Table 105.11 — The common conventions of this reference

<assert.h> — checking a contract while it runs#

Body: chapter 80(the chapter), chapter 53(contracts), chapter 54(undefined behaviour).

The whole header is one macro and one name that switches it off. That it is a macro and not a function is the point — only a macro can print the file and line where the check failed.

NameFormArguments and returnWhat it does · ★trap
assertvoid assert(scalar expression)takes one expression; returns nothingprints a diagnostic and calls abort if the expression is false. ★ It vanishes entirely when NDEBUG is defined, so nothing with a side effect may go inside: assert(f()) does not call f in a release build
NDEBUGmacroonly whether it is defined matters, not its valuewhen defined, assert does nothing. ★ What counts is whether it is defined at the point where <assert.h> is included — the decision is remade on each include

Table 105.12 — <assert.h> entry by entry

<errno.h> — where a failure leaves its reason#

Body: chapter 80(the chapter), chapter 53(errors as values).

There are no functions here: one integer (errno), three values the standard fixes, and one Annex K type. ★ The standard defines only three values; the familiar ones such as ENOENT come from POSIX.

NameFormArguments and returnWhat it does · ★trap
errnoa modifiable lvalue written as int errnocan be read and written★ It is not guaranteed to be a variable — a macro gives you a per-thread location. ★ A successful call does not clear it, so set it to 0 before the call and read it only after you have seen a failure
EDOMinteger constant expressiondistinct non-zero valuesdomain error — the argument is not mathematically allowed, as in sqrt(-1.0) (chapter 78)
ERANGEinteger constant expressionsamethe value is outside the representable range — overflow in strtol (chapter 71), divergence in exp
EILSEQinteger constant expressionsamethe byte sequence is not a valid character in that encoding — multibyte conversion (chapter 75)
errno_ttypethe same as int★K an Annex K name; optional, so it may be absent (chapter 83)

Table 105.13 — <errno.h> entry by entry

<setjmp.h> — writing down a place to come back to#

Body: chapter 82(the chapter), chapter 80(diagnosis and control), chapter 5(where things live).

Two names, and neither behaves like an ordinary function. setjmp returns twice, and longjmp does not return at all.

NameFormArguments and returnWhat it does · ★trap
setjmpint setjmp(jmp_buf env)records the current place in env. Zero when called directly; when reached by longjmp, the value that call passed★ It is a macro, and the standard narrows where it may appear: the whole controlling expression of a condition, or a statement on its own, and little else. x = setjmp(env); is not allowed
longjmpvoid longjmp(jmp_buf env, int val)returns to the place recorded in env. Does not return★ A val of 0 becomes 1 — it has to be distinguishable from the first pass. ★ If the function that called setjmp has already returned, the behaviour is undefined. ★ Automatic variables that are not volatile and changed in between have indeterminate values
jmp_bufarray typewhat setjmp and longjmp pass between them★ It is not guaranteed to survive being copied wholesale — leave it where it is

Table 105.14 — <setjmp.h> entry by entry

<stdarg.h> — walking arguments whose number is unknown#

Body: chapter 63(the chapter), chapter 69(format strings).

All four are macros. Open with va_start, take one at a time with va_arg, close with va_end — and every trap in this header grows from one root: it cannot work out the types by itself.

NameFormArguments and returnWhat it does · ★trap
va_startvoid va_start(va_list ap, ...)makes ap ready to use★ Since C23 the last named parameter need not be given, which is what makes a variadic function with no named parameter at all possible
va_argtype va_arg(va_list ap, type)takes the next argument as type★ If it differs from the type actually passed, the behaviour is undefined. Write the type after default argument promotion — float arrives as double, char and short as int
va_copyvoid va_copy(va_list dest, va_list src)copies the current state of src into destC99. Use it when the same list must be walked twice (the idiom of measuring with vsnprintf and then printing). ★ The copy needs its own va_end
va_endvoid va_end(va_list ap)closes ap★ What was opened must be closed. Leaving it out usually looks harmless, but the standard calls it undefined behaviour
va_listtypeholds the state of the walk★ Once walked it cannot be walked again — take a va_copy first if you need to

Table 105.15 — <stdarg.h> entry by entry

<stddef.h> — names for the things that had none#

Body: chapter 37(the null triplet), chapter 27(kinds of type), chapter 4(alignment).

No functions. What lives here are the names other headers lean on — the type that measures a size, the distance between two addresses, and null.

NameFormWhat it isWhat it does · ★trap
size_tunsigned integer typethe type sizeof yieldsholds sizes and counts. ★ It is unsigned — a subtraction that would go negative wraps to an enormous value instead (chapter 6)
ptrdiff_tsigned integer typethe type of the difference of two pointers★ The contract covers only two places within the same array (chapter 38)
wchar_tinteger typethe type that holds a wide character★ Neither its size nor its encoding is fixed by the standard — four bytes on Linux, two on Windows (chapter 75)
max_align_tobject typethe type with the strictest fundamental alignmentthe yardstick that the address returned by malloc satisfies (chapter 4)
nullptr_ttypethe type of nullptrC23. ★ A type with exactly one value — nullptr itself (chapter 87)
rsize_tthe same as size_ta name used by Annex K★K optional, so it may be absent (chapter 83)
NULLmacro expanding to a null pointer constant“points at nothing”★ It is not guaranteed to be 0 — machines existed whose representation was not zero (chapter 37)
offsetofsize_t offsetof(type, member-designator)the distance from the start of a struct to a member★ Not usable on bit-fields. It underlies serialisation and the container idioms

Table 105.16 — <stddef.h> entry by entry

<stdbool.h> and <stdalign.h> — the two headers that emptied out#

Body: chapter 87(from macro to keyword), chapter 31(booleans), chapter 4(alignment).

Neither header has anything left to list — and that is the entry. The names C99 and C11 lent through macros became words of the language in C23. The headers remain only so that older code keeps compiling.

HeaderWhat it used to giveNow
<stdbool.h>bool, true, false as macrosall three are keywords; including it is optional
<stdalign.h>alignas and alignof as macrosboth are keywords; same story

Table 105.17 — How they came to be empty

★ So there is no reason to include either in new code. The standard kept them harmless to include on purpose — so that old code need not be touched.

<iso646.h> and <stdnoreturn.h> — one scar and one retired name#

Body: chapter 8(ISO 646 and trigraphs), chapter 25(_Noreturn), chapter 87(from macro to keyword).

Both headers contain no functions at all, so they do not fit the shape of the reference tables. They are standard headers all the same, so they sit here.

<iso646.h> gives eleven macros that let operators be written as words. The point is the national variants of ISO 646 seen in chapter 8 — character sets where positions such as &, |, ^ and ~ hold other letters — so that C can still be written in them. If trigraphs were the character-level answer to that problem, this header is the word-level answer.

MacroExpands toMacroExpands to
and&&not_eq!=
and_eq&=or||
bitand&or_eq|=
bitor|xor^
compl~xor_eq^=
not!

Table 105.18 — The eleven names <iso646.h> gives

★ In C these are macros, so they mean something only once the header is included. In C++ the same names are alternative tokens of the language from the start. That is why a variable named and is fine in C and breaks under a C++ compiler.

<stdnoreturn.h> gives a single macro, noreturn, which expands to _Noreturn. C23 marked this macro and the header obsolescent, together with the _Noreturn function specifier (N3220 §7.25). New code uses the [[noreturn]] attribute (chapter 25).

★ In a file that includes this header, noreturn is a macro, so [[noreturn]] becomes [[_Noreturn]] after preprocessing. That is exactly why the standard separately accepts [[_Noreturn]] as an equivalent attribute (the footnote in §6.7.13.7) — so the old header and the new attribute can meet in one file without breaking.

<limits.h> — where the integers end#

Body: chapter 6(representing integers), chapter 27(kinds of type), chapter 28(integers are finite).

No functions. For each type there is a triple: smallest value, largest value, bit width. Learn the rule and there are no thirty-three names to memorise.

SuffixWhatExample
_MINthe smallest value the type holdsINT_MIN
_MAXthe largestINT_MAX
_WIDTHthe bit width, sign bit includedINT_WIDTH — added by C23

Table 105.19 — How to read the names

★ Unsigned types have no _MIN: it is zero.

TypeMinimumMaximumWidth · ★trap
charCHAR_MINCHAR_MAXCHAR_WIDTH. ★ Whether it is signed is up to the implementation, so CHAR_MIN may be 0
signed charSCHAR_MINSCHAR_MAXSCHAR_WIDTH
unsigned char0UCHAR_MAXUCHAR_WIDTH
shortSHRT_MINSHRT_MAXSHRT_WIDTH
unsigned short0USHRT_MAXUSHRT_WIDTH
intINT_MININT_MAXINT_WIDTH
unsigned int0UINT_MAXUINT_WIDTH
longLONG_MINLONG_MAXLONG_WIDTH. ★ Eight bytes on 64-bit Linux, four on Windows
unsigned long0ULONG_MAXULONG_WIDTH
long longLLONG_MINLLONG_MAXLLONG_WIDTH
unsigned long long0ULLONG_MAXULLONG_WIDTH
bool0BOOL_MAXBOOL_WIDTH. Added by C23 — each is 1

Table 105.20 — <limits.h> entry by entry

NameWhat★trap
CHAR_BITbits in a byte★ The standard does not promise 8. In practice no machine in use today says otherwise (chapter 6)
MB_LEN_MAXthe most bytes one multibyte character can take in any localedifferent from MB_CUR_MAX, which is the current locale’s value (chapter 75)
BITINT_MAXWIDTHthe largest N allowed in _BitInt(N)C23. Guaranteed to be at least ULLONG_WIDTH

Table 105.21 — The three that belong to no type

<float.h> — where the reals end#

Body: chapter 7(representing numbers), chapter 52(the mathematics of approximation), chapter 78(working with numbers).

No functions. Sixty-odd names look like a lot, but they are three prefixes × fifteen suffixes plus a few that belong to no type. The prefixes are FLT_ (float), DBL_ (double) and LDBL_ (long double).

SuffixWhatNames★trap
_MANT_DIGdigits in the significand, in base FLT_RADIXFLT_MANT_DIG, DBL_MANT_DIG, LDBL_MANT_DIGthis is where precision comes from
_DIGdecimal digits that survive a round tripFLT_DIG, DBL_DIG, LDBL_DIGusually 15 for double
_DECIMAL_DIGdigits needed to write the value out and read it back unchangedFLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG★ Not the same as _DIG — this one is larger (17 for double)
_EPSILONthe gap between 1 and the next larger valueFLT_EPSILON, DBL_EPSILON, LDBL_EPSILON★ It is not “a small enough number” — using it directly to compare large values is wrong
_MINthe smallest normalised positive valueFLT_MIN, DBL_MIN, LDBL_MIN★ Not the smallest positive value — that is _TRUE_MIN
_TRUE_MINthe smallest positive value, subnormals includedFLT_TRUE_MIN, DBL_TRUE_MIN, LDBL_TRUE_MINequals _MIN where there are no subnormals
_MAXthe largest finite valueFLT_MAX, DBL_MAX, LDBL_MAXbeyond it lies infinity
_NORM_MAXthe largest normalised finite valueFLT_NORM_MAX, DBL_NORM_MAX, LDBL_NORM_MAXequals _MAX in binary formats
_MIN_EXP, _MAX_EXPexponent range in base FLT_RADIXFLT_MIN_EXP, DBL_MIN_EXP, LDBL_MIN_EXP / FLT_MAX_EXP, DBL_MAX_EXP, LDBL_MAX_EXP
_MIN_10_EXP, _MAX_10_EXPexponent range in decimalFLT_MIN_10_EXP, DBL_MIN_10_EXP, LDBL_MIN_10_EXP / FLT_MAX_10_EXP, DBL_MAX_10_EXP, LDBL_MAX_10_EXP
_HAS_SUBNORMwhether subnormals existFLT_HAS_SUBNORM, DBL_HAS_SUBNORM, LDBL_HAS_SUBNORMone of 1, 0 or −1 (unknown)
_IS_IEC_60559whether it follows IEC 60559 (IEEE 754)FLT_IS_IEC_60559, DBL_IS_IEC_60559, LDBL_IS_IEC_60559added by C23
_SNANa signalling NaNFLT_SNAN, DBL_SNAN, LDBL_SNANC23. Present when the type has one

Table 105.22 — What each suffix means — all three prefixes take them

NameWhat★trap
FLT_RADIXthe base of the exponent★ Despite the FLT_ prefix it applies to all three types. In practice it is 2
FLT_ROUNDSthe current rounding direction★ Not a constant — it can change while the program runs (fesetround, chapter 78)
FLT_EVAL_METHODthe width intermediate results are computed in★ It means arithmetic on float may be carried out in double
DECIMAL_DIGthe _DECIMAL_DIG of the widest typesuperseded in C23 — use LDBL_DECIMAL_DIG
CR_DECIMAL_DIGdigits for correctly rounded decimal conversionC23
INFINITYfloat infinitydefined only where it exists
NANa quiet float NaN★ NAN == NAN is false (chapter 52)

Table 105.23 — The names that belong to no type

★ Decimal floating point follows the same rule, with 32, 64 or 128 in place of the N: DECN_MANT_DIG, DECN_EPSILON, DECN_MAX, DECN_MIN, DECN_MAX_EXP, DECN_MIN_EXP, DECN_TRUE_MIN and DECN_SNAN, together with DEC_EVAL_METHOD, DEC_INFINITY and DEC_NAN. It is optional, and many implementations lack it.

<stdint.h> — integers with the width nailed down#

Body: chapter 6(representing integers), chapter 27(kinds of type), chapter 51(working with bits).

The width of int differs from machine to machine, and this header faces that squarely. There are no functions, only types and macros, and the N in the names stands for an actual width — 8, 16, 32, 64.

FormPromise★trap
intN_t, uintN_texactly N bits, no padding, two’s complement★ Not guaranteed to exist — undefined on a machine without that width
int_leastN_t, uint_leastN_tthe smallest type with at least N bits★ These always exist. The most portable choice
int_fastN_t, uint_fastN_tat least N bits and fast on that machine★ “Fast” is the implementation’s judgement — it may be wider than you expect

Table 105.24 — Three families — what each promises

NameWhatCompanions★trap
intmax_t, uintmax_tthe widest integer typesINTMAX_MIN, INTMAX_MAX, INTMAX_WIDTH, UINTMAX_MAX, UINTMAX_WIDTH★ _BitInt does not take part in this
intptr_t, uintptr_tan integer a pointer can be put in and taken back out ofINTPTR_MIN, INTPTR_MAX, INTPTR_WIDTH, UINTPTR_MAX, UINTPTR_WIDTH★ Optional. And whether the recovered pointer is usable is a question of provenance (chapter 38)
exact widthintN_t, uintN_tINTN_MIN, INTN_MAX, INTN_WIDTH, UINTN_MAX, UINTN_WIDTHN is 8, 16, 32 or 64
at least N bitsint_leastN_t, uint_leastN_tINT_LEASTN_MIN, INT_LEASTN_MAX, INT_LEASTN_WIDTH, UINT_LEASTN_MAX, UINT_LEASTN_WIDTH
the fast onesint_fastN_t, uint_fastN_tINT_FASTN_MIN, INT_FASTN_MAX, INT_FASTN_WIDTH, UINT_FASTN_MAX, UINT_FASTN_WIDTH
writing constantsmakes a constant of that typeINTN_C, UINTN_C, INTMAX_C, UINTMAX_C★ Not values — macros that attach a suffix to a literal

Table 105.25 — <stdint.h> entry by entry

NameLimit of whatNote
SIZE_MAX, SIZE_WIDTHsize_tthe ceiling when computing an allocation size
PTRDIFF_MIN, PTRDIFF_MAXptrdiff_t
WCHAR_MIN, WCHAR_MAX, WCHAR_WIDTHwchar_t(chapter 75)
WINT_MIN, WINT_MAX, WINT_WIDTHwint_tmust be able to hold WEOF
SIG_ATOMIC_MIN, SIG_ATOMIC_MAX, SIG_ATOMIC_WIDTHsig_atomic_tthe only type a signal handler may touch (chapter 80)
RSIZE_MAXwhere Annex K considers a size “too large”★K optional (chapter 83)

Table 105.26 — Limits belonging to types from other headers

<inttypes.h> — printing and reading those integers#

Body: chapter 69(format strings), chapter 71(from string to number), chapter 6(representing integers).

It includes <stdint.h> and adds what to write in the printf format. Printing an int64_t with %ld is right on one machine and wrong on another — this header removes that question.

NameFormArguments and returnWhat it does · ★trap
imaxabsintmax_t imaxabs(intmax_t j)the absolute value★ The absolute value of the most negative number is not representable — undefined behaviour
imaxdivimaxdiv_t imaxdiv(intmax_t numer, intmax_t denom)quotient and remainder togetherimaxdiv_t is a struct with quot and rem
strtoimaxintmax_t strtoimax(const char * restrict nptr, char ** restrict endptr, int base)the value read; failure through endptr and errno★ The contract is that of strtol — clear errno before the call (chapter 71)
strtoumaxuintmax_t strtoumax(const char * restrict nptr, char ** restrict endptr, int base)same★ Unsigned, yet it accepts - and gives you the wrapped value
wcstoimax, wcstoumaxthe wide-string versionssame(chapter 75)
intmax_t, uintmax_t, wchar_ttypesre-exposed from <stdint.h> and <stddef.h>

Table 105.27 — <inttypes.h> entry by entry

FormWhatExample
PRIBNformat for printing an exact-width type — B stands for d, i, o, u or xPRId32, PRIu64
PRIBLEASTN, PRIBFASTNformats for the least and fast typesPRIdLEAST16, PRIuFAST32
PRIBMAX, PRIBPTRformats for intmax_t and intptr_tPRIdMAX, PRIdPTR
PRIXN, PRIXLEASTN, PRIXFASTN, PRIXMAX, PRIXPTRthe uppercase hexadecimal versions of the samePRIX64

Table 105.28 — How to read the format macros

★ You use them by concatenating strings: printf("%" PRId64 "\n", v);. For reading there is a matching SCN… family under the same rule.

<stdbit.h> — counting bits, the standard way#

Body: chapter 51(the chapter), chapter 29(integer operations).

A C23 header. Bit counting, which until now existed only as compiler extensions such as __builtin_popcount, became standard. One rule reads the names: they begin with stdc_, each type has its own version with a _uc, _us, _ui, _ul or _ull suffix, and the name without a suffix is a type-generic macro.

NameWhat it counts★trap · use
stdc_leading_zeroszero bits at the frontit depends on the width, so the type matters
stdc_leading_onesone bits at the front
stdc_trailing_zeroszero bits at the backtells you what power of two divides the value
stdc_trailing_onesone bits at the back
stdc_first_leading_zero, stdc_first_leading_onethe first such position from the front, counting from 1★ Zero when there is none — 0 is not “the first position”
stdc_first_trailing_zero, stdc_first_trailing_onethe first such position from the backsame
stdc_count_zeros, stdc_count_oneshow many bits are zero, how many are onestdc_count_ones is the population count
stdc_has_single_bitwhether exactly one bit is setthe power-of-two test — ★ false for 0
stdc_bit_widththe fewest bits that hold the valuestdc_bit_width(0) is 0
stdc_bit_floor, stdc_bit_ceilthe nearest power of two at or below, and at or above★ stdc_bit_ceil is undefined behaviour when it would overflow

Table 105.29 — <stdbit.h> entry by entry — written with the type-generic names

★ Test for it with __STDC_VERSION_STDBIT_H__. This header also provides the names that answer the endianness question — __STDC_ENDIAN_LITTLE__, __STDC_ENDIAN_BIG__ and __STDC_ENDIAN_NATIVE__ (chapter 6).

<locale.h> — changing whose conventions apply#

Body: chapter 73(the chapter), chapter 74(numbers, money, time, collation), chapter 8(character sets).

Only two functions, but between them they change how the whole program behaves. A locale is global state — nearly every trap in this header follows from that.

NameFormArguments and returnWhat it does · ★trap
setlocalechar *setlocale(int category, const char *locale)takes a category and a name, returns the current locale name; null on failureA null locale asks without changing. ★ The returned string may be overwritten by the next call — copy it if you need it. ★ At startup it is always "C". ★ Calling it from several threads is not safe
localeconvstruct lconv *localeconv(void)a struct holding the current numeric and monetary formats★ What it returns must not be modified, and setlocale may change its contents — read the values when you need them
LC_ALLcategoryeverything★ Switching it wholesale to something other than "C" changes even the decimal point printf writes — a common way to break a file format
LC_COLLATEcategorycollation orderwhat strcoll and strxfrm consult
LC_CTYPEcategorycharacter classes and casewhat <ctype.h> and multibyte conversion consult
LC_MONETARYcategorymonetary formatread it through localeconv and format it yourself
LC_NUMERICcategorydecimal point and grouping★ printf and strtod consult this
LC_TIMEcategorydate and time formatwhat strftime consults
NULLmacrothe one from <stddef.h>

Table 105.30 — <locale.h> entry by entry

<wctype.h> — the kinds of a wide character#

Body: chapter 75(wide characters), chapter 73(locales), chapter 8(character sets).

The wide counterpart of <ctype.h>; think of it as the same names with isw and tow in front. What it adds are two pairs that name a class at run time (wctype with iswctype, wctrans with towctrans).

NameWhat is true · what it doesNote · ★trap
iswalnuma letter or a digitsame meaning as its <ctype.h> counterpart
iswalphaa letterthe locale decides
iswblanka blankC99
iswcntrla control character
iswdigit0–9★ independent of the locale
iswgraphprinting, space excluded
iswlowerlowercase
iswprintprinting
iswpunctpunctuation
iswspacewhitespace
iswupperuppercase
iswxdigita hexadecimal digit★ independent of the locale
towlower, towupperthe corresponding case, or unchanged★ The one-character-to-one-character limit is still there
wctypeturns a class name such as "alpha" into a wctype_tzero for an unknown name
iswctypewhether the character is in that classlocale-defined classes work too
wctransturns a mapping name such as "tolower" into a wctrans_tzero for an unknown name
towctransapplies the mapping wctrans returned
wint_ta type holding a wide character or WEOF★ Not wchar_t — WEOF has to fit
WEOFthe wint_t value meaning end of input★ Not guaranteed to be -1
wctype_t, wctrans_thandles for a class and a mapping

Table 105.31 — <wctype.h> entry by entry

<uchar.h> — characters with the Unicode width nailed down#

Body: chapter 77(Unicode), chapter 75(multibyte conversion), chapter 8(character sets).

The standard’s answer to wchar_t differing between machines (chapter 75). The width is in the name, and the conversion functions carry state, one character at a time.

NameFormArguments and returnWhat it does · ★trap
mbrtoc8size_t mbrtoc8(char8_t * restrict pc8, const char * restrict s, size_t n, mbstate_t * restrict ps)bytes consumed; special values report the situationC23. ★ It may yield one UTF-8 byte at a time, so it has to be called repeatedly
c8rtombsize_t c8rtomb(char *s, char8_t c8, mbstate_t *ps)bytes writtenC23. The other direction
mbrtoc16size_t mbrtoc16(char16_t * restrict pc16, const char * restrict s, size_t n, mbstate_t * restrict ps)same★ Because of surrogate pairs, one character can come out in two calls
c16rtombsize_t c16rtomb(char *s, char16_t c16, mbstate_t *ps)bytes writtenthe other direction
mbrtoc32size_t mbrtoc32(char32_t * restrict pc32, const char * restrict s, size_t n, mbstate_t * restrict ps)sameone code point per call — the easiest of the three to work with
c32rtombsize_t c32rtomb(char *s, char32_t c32, mbstate_t *ps)bytes writtenthe other direction
char8_t, char16_t, char32_ttypescode units of UTF-8, UTF-16 and UTF-32★ The widths are fixed, but char8_t arrived in C23
mbstate_ttypethe state a conversion carries★ Zero it once and keep passing the same one — a fresh one per string
size_ttypethe one from <stddef.h>

Table 105.32 — <uchar.h> entry by entry

★ The special size_t return values are the heart of the contract: 0 (a null character), (size_t)-1 (encoding error, errno set to EILSEQ), (size_t)-2 (not enough bytes to decide yet) and (size_t)-3 (something was left in the state, so no input was consumed).

<signal.h> — interruption from outside#

Body: chapter 81(the chapter), chapter 80(diagnosis and control), chapter 11(interrupts).

Two functions, but the weight of this header is not in them — it is in the contract about what a handler is allowed to do. What the standard permits is startlingly little.

NameFormArguments and returnWhat it does · ★trap
signalvoid (*signal(int sig, void (*func)(int)))(int)installs a handler for a signal; returns the previous one, or SIG_ERR★ The form looks hard, but it is only “takes a function pointer taking int, returns the same”. ★ The handler may be reset to the default once it has run — the standard does not say which
raiseint raise(int sig)sends a signal to itself; 0 on successthis is what abort does with SIGABRT
sig_atomic_tinteger typethe only type a handler and the program may share★ Write it as volatile sig_atomic_t. Beyond that there is almost nothing a handler may touch
SIG_DFL, SIG_IGNvalues passed to signaldefault action; ignore
SIG_ERRthe failure return of signal★ It is not null — compare against it explicitly
SIGABRTabnormal terminationraised by abort
SIGFPEan erroneous arithmetic operationdivision by zero and the like★ Despite the name it also arises in integer division
SIGILLan invalid instruction
SIGINTan interactive attention requestusually Ctrl-C
SIGSEGVan invalid access to storage★ Trying to “recover” here is almost always a mistake
SIGTERMa termination requesta polite request from the sender

Table 105.33 — <signal.h> entry by entry

★ Inside a handler the standard clearly allows three things: writing to a volatile sig_atomic_t, calling signal again, and ending with abort, _Exit or quick_exit. Not printf, and not malloc (chapter 81).

<fenv.h> — reaching into the floating-point environment#

Body: chapter 78(working with numbers), chapter 52(the mathematics of approximation), chapter 7(representing numbers).

This header handles rounding direction and exception flags directly. ★ To use it you must first turn on #pragma STDC FENV_ACCESS ON — otherwise the compiler assumes the program does not touch the environment, and moves the arithmetic.

FamilyNamesMeaning
exception flagsFE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOWdivision by zero, inexact, invalid operation, overflow, underflow
all of themFE_ALL_EXCEPTthe bitwise union of the above
rounding directionsFE_TONEAREST, FE_TOWARDZERO, FE_UPWARD, FE_DOWNWARD, FE_TONEARESTFROMZEROto nearest (the default), toward zero, up, down, ties away from zero
default environment and modeFE_DFL_ENV, FE_DFL_MODE, FE_DYNAMICthe environment at startup, the default mode, determined at run time
decimalFE_DEC_TONEAREST, FE_DEC_TOWARDZERO, FE_DEC_UPWARD, FE_DEC_DOWNWARD, FE_DEC_TONEARESTFROMZEROthe same for decimal floating point
pragmasFENV_ACCESS, FENV_ROUND, FENV_DEC_ROUND, STDCused as #pragma STDC …
otherFE_SNANS_ALWAYS_SIGNALwhether signalling NaNs always signal

Table 105.34 — Exception flags and rounding directions

NameWhat it doesNote · ★trap
feclearexceptclears flags★ The contract is to clear before you measure
fetestexceptasks which flags are raisedreturns the union of those asked about
feraiseexcept, fesetexceptraises flags — signalling, and quietlyfesetexcept is C23
fegetexceptflag, fesetexceptflagsaves flag state in a fexcept_t and restores it
fetestexceptflagasks about a saved stateC23
fegetround, fesetroundreads and sets the rounding directionFLT_ROUNDS reflects it
fegetmode, fesetmodereads and sets the whole mode as a femode_tC23
fegetenv, fesetenvreads and sets the whole environment as a fenv_t
feholdexceptsaves the environment, clears flags, goes quietthe opening half of a wrapped computation
feupdateenvrestores the saved environment and re-raises what happened meanwhilethe closing half
fe_dec_getround, fe_dec_setroundrounding direction for decimal floating pointC23
fenv_t, fexcept_t, femode_ttypes holding the environment, the flags and the mode

Table 105.35 — <fenv.h> entry by entry

<tgmath.h> — it picks the one that fits the type#

Body: chapter 78(the chapter), chapter 52(the mathematics of approximation).

A header with no new names to list. It includes <math.h> and <complex.h> and covers their functions with type-generic macros of the same name.

Argument typeWhat is chosenExample
floatthe f-suffixed onesqrt(x) → sqrtf
double, integersthe unsuffixed onesqrt(x) → sqrt — ★ integers are promoted to double
long doublethe l-suffixed onesqrt(x) → sqrtl
complexthe c-prefixed onesqrt(z) → csqrt

Table 105.36 — What it picks

★ So with <tgmath.h> included there is no need to pick sqrtf or sqrtl by hand. They are macros, though: they cannot be passed as function pointers, and the standard had to promise separately that the argument is not evaluated twice.

<complex.h> — complex numbers#

Body: chapter 78(working with numbers), chapter 52(the mathematics of approximation), chapter 27(kinds of type).

An optional header — it is absent when __STDC_NO_COMPLEX__ is defined. One rule reads the names: put c in front of the <math.h> function, and add f or l for the float and long double versions (csqrtf, csqrtl).

NameWhat it returns★trap
crealthe real part
cimagthe imaginary part
cargthe argument — the angle in the complex planethe range is −𝜋 to 𝜋
cabsthe absolute value — distance from the origin★ Built so that the intermediate computation does not overflow
conjthe complex conjugateflips the sign of the imaginary part
cprojprojection onto the Riemann spheregathers the infinities into one

Table 105.37 — The ones that take a value apart

FamilyNamesNote
exponential and logarithmcexp, clog, cpow, csqrt★ clog and csqrt have branch cuts: on the negative real axis the answer depends on the sign of zero
trigonometriccsin, ccos, ctan
inverse trigonometriccasin, cacos, catanthey have branch cuts
hyperboliccsinh, ccosh, ctanh
inverse hyperboliccasinh, cacosh, catanhthey have branch cuts

Table 105.38 — Those that pair with <math.h>

NameWhat★trap
CMPLX, CMPLXF, CMPLXLbuild a complex number from a real and an imaginary part★ x + y*I is not always right — if y is an infinity or a NaN the multiplication ruins the answer. That is why C11 added these macros
CX_LIMITED_RANGEturned on with #pragma STDC CX_LIMITED_RANGE ONit says the slower overflow-avoiding formulas for multiplication and division may be skipped
STDCthe first word of the pragma

Table 105.39 — Making values and choosing the arithmetic

★ The imaginary unit is I, built on _Complex_I and _Imaginary_I. Pure imaginary types are optional, so check __STDC_IEC_559_COMPLEX__ as well.

<threads.h> — the standard’s own threads#

Body: chapter 84(the chapter), chapter 85(atomic operations), chapter 11(interrupts).

Optional — absent when __STDC_NO_THREADS__ is defined, and many implementations do not have it, so in practice POSIX threads or the Windows API are common instead. Prefixes divide the names: thrd_ (threads), mtx_ (mutexes), cnd_ (condition variables), tss_ (thread-specific storage).

NameWhat it doesNote · ★trap
thrd_createcreates a thread and runs a function in itthe function’s form is thrd_start_t — int (*)(void *)
thrd_joinwaits for it to finish and takes its result★ Join it or detach it — one of the two must happen
thrd_detachlets it clean itself up when it ends★ A detached thread cannot be joined
thrd_exitends the current threadthe tss destructors run
thrd_currenta handle to the current thread
thrd_equalwhether two handles are the same thread★ Do not compare with == — the contents of a thrd_t are unspecified
thrd_sleepsleeps for a given durationit can hand back the remaining time
thrd_yieldgives up its turn

Table 105.40 — Threads themselves — thrd_

NameWhat it doesNote · ★trap
mtx_init, mtx_destroycreates and destroys a mutexpick mtx_plain, mtx_timed or mtx_recursive
mtx_lock, mtx_unlocklocks and unlocks★ The thread that locked is the one that unlocks
mtx_trylocklocks if it can, returns at once if it cannot
mtx_timedlockwaits only until a given timeonly for one made mtx_timed
cnd_init, cnd_destroycreates and destroys a condition variable
cnd_wait, cnd_timedwaitreleases the mutex, waits, and takes it again on waking★ Check again why you woke — spurious wakeups happen. Wrap it in a while
cnd_signal, cnd_broadcastwakes one, wakes all
call_onceruns exactly once however many threads call itgive it a once_flag set to ONCE_FLAG_INIT

Table 105.41 — Getting along — mtx_, cnd_, call_once

NameWhatNote
tss_create, tss_deletecreates and deletes a keya destructor comes with it — tss_dtor_t
tss_get, tss_setreads and writes this thread’s value★ TSS_DTOR_ITERATIONS bounds how many times destructors run
thrd_t, mtx_t, cnd_t, tss_tthe handle typesdo not look inside them
thrd_start_t, tss_dtor_tfunction pointer types

Table 105.42 — Thread-specific storage, and the types

★ The returns are thrd_success, thrd_busy, thrd_error, thrd_nomem and thrd_timedout. Zero is not success here — the convention differs from the rest of C.

<stdatomic.h> — operations that cannot be split#

Body: chapter 85(the chapter), chapter 84(threads), chapter 12(the memory ladder).

Optional — absent when __STDC_NO_ATOMICS__ is defined. A rule reads the names: they begin with atomic_, and a partner ending in _explicit is the one that chooses the memory order itself. Without the suffix the strongest order (memory_order_seq_cst) is used.

NameWhat it does★trap
atomic_initgives an atomic object its first value★ This is not itself atomic — do it before anyone else can see the object
atomic_load, atomic_load_explicitreads
atomic_store, atomic_store_explicitwrites
atomic_exchange, atomic_exchange_explicitreplaces and returns the old value
atomic_compare_exchange_strong, atomic_compare_exchange_strong_explicitreplaces if the value is the one expected★ On failure it writes the current value into the expected slot
atomic_compare_exchange_weak, atomic_compare_exchange_weak_explicitthe same, but may fail for no reasonso it is used inside a loop — and it is faster
atomic_fetch_key, atomic_fetch_key_explicitkey stands for add, sub, or, xor or andreturns the old value
atomic_flag_test_and_set, atomic_flag_test_and_set_explicitsets the flag and returns its previous state★ atomic_flag is the one type that is always lock-free
atomic_flag_clear, atomic_flag_clear_explicitclears the flaginitialise it with ATOMIC_FLAG_INIT
atomic_is_lock_freewhether that type is lock-free★ The per-type ATOMIC_…_LOCK_FREE macros can answer at compile time
atomic_thread_fence, atomic_signal_fenceraise an ordering fence — between threads, and against a signal handler
kill_dependencybreaks a dependency chainit goes with memory_order_consume, which is rarely used in practice

Table 105.43 — The operations of <stdatomic.h>

FamilyNamesNote
charactersatomic_char8_t, atomic_char16_t, atomic_char32_t, atomic_wchar_t
fixed widthatomic_int_least8_t, atomic_int_least16_t, atomic_int_least32_t, atomic_int_least64_t and the unsigned atomic_uint_least8_t, atomic_uint_least16_t, atomic_uint_least32_t, atomic_uint_least64_t
the fast onesatomic_int_fast8_t, atomic_int_fast16_t, atomic_int_fast32_t, atomic_int_fast64_t and atomic_uint_fast8_t, atomic_uint_fast16_t, atomic_uint_fast32_t, atomic_uint_fast64_t
the restatomic_intmax_t, atomic_uintmax_t, atomic_intptr_t, atomic_uintptr_t, atomic_size_t, atomic_ptrdiff_twriting _Atomic yourself works too

Table 105.44 — The type names — atomic_ in front

<wchar.h> — everything about wide characters#

Body: chapter 75(wide characters ①), chapter 76(wide characters ②), chapter 69(reading and writing).

One of the largest headers, and yet there is almost nothing new to learn: it carries the functions of <string.h>, <stdio.h> and <stdlib.h> over to wide characters. Three rules cover it — strings take wcs, memory blocks take wmem, and the I/O names carry a w.

FamilyNamesNote · ★trap
lengthwcslen★ Code units, not characters — they differ where wchar_t is UTF-16
copyingwcscpy, wcsncpy, wmemcpy, wmemmove★ wcsncpy inherits every trap of strncpy, terminator included
appendingwcscat, wcsncat
comparingwcscmp, wcsncmp, wmemcmp, wcscoll, wcsxfrmwcscoll and wcsxfrm follow the locale’s order (chapter 74)
searchingwcschr, wcsrchr, wcsstr, wcspbrk, wcsspn, wcscspn, wmemchr
splittingwcstok★ You hold the state yourself — unlike strtok it takes a third argument
fillingwmemset
time formattingwcsftimethe wide version of strftime

Table 105.45 — Strings and memory — the <string.h> counterparts

FamilyNamesNote · ★trap
single characterbtowc, wctob★ Meaningful only for characters that are a single byte
carrying statembrtowc, wcrtomb, mbrlen, mbsinit★ Zero an mbstate_t and keep passing the same one
whole stringsmbsrtowcs, wcsrtombs★ They update the source pointer so conversion can be resumed
to numberswcstol, wcstoul, wcstod, wcstof, wcstoldthe contract of the strtol family (chapter 71)
decimal floating pointwcstod32, wcstod64, wcstod128optional

Table 105.46 — Conversion — between bytes and wide, and to numbers

FamilyNamesNote · ★trap
one characterfgetwc, getwc, getwchar, fputwc, putwc, putwchar, ungetwcthe end is WEOF
one linefgetws, fputws
formatted outputwprintf, fwprintf, swprintf, vwprintf, vfwprintf, vswprintf★ swprintf takes a size, like snprintf
formatted inputwscanf, fwscanf, swscanf, vwscanf, vfwscanf, vswscanf
choosing the widthfwide★ A stream sets into byte or wide orientation — the two must not be mixed (chapter 76)

Table 105.47 — Input and output — the <stdio.h> counterparts

FamilyNamesNote
typeswchar_t, wint_t, mbstate_t, size_t, FILEre-exposed from other headers
macrosWEOF, WCHAR_MIN, WCHAR_MAX, NULL
Annex Kwcscpy_s, wcsncpy_s, wcscat_s, wcsncat_s, wmemcpy_s, wmemmove_s, wcstok_s, wcsnlen_s, wcrtomb_s, mbsrtowcs_s, wcsrtombs_s, wprintf_s, fwprintf_s, swprintf_s, snwprintf_s, vwprintf_s, vfwprintf_s, vswprintf_s, vsnwprintf_s, wscanf_s, fwscanf_s, swscanf_s, vwscanf_s, vfwscanf_s, vswscanf_s★K optional and not widely implemented (chapter 83)

Table 105.48 — Types, macros and Annex K

<time.h> — instants and durations#

Body: chapter 79(the chapter), chapter 74(time formats), chapter 98(the outside world).

Learn that there are three ways of counting time and the rest are functions moving between them — calendar time (time_t), broken-down time (struct tm) and processor time (clock_t).

NameFormArguments and returnWhat it does · ★trap
timetime_t time(time_t *timer)the current calendar time, or (time_t)-1 if unavailable★ The standard fixes neither the meaning nor the resolution of time_t — Unix seconds are not guaranteed
difftimedouble difftime(time_t time1, time_t time0)the difference in seconds★ Do not compute it by subtraction — time_t need not be in seconds
clockclock_t clock(void)processor time, or (clock_t)-1★ Not wall-clock time. Divide by CLOCKS_PER_SEC for seconds. ★ It can wrap
mktimetime_t mktime(struct tm *timeptr)broken-down time to calendar time★ It modifies its argument — normalising out-of-range fields and filling in tm_wday and tm_yday. That is what makes it the tool for “three months from now”
localtime, gmtimestruct tm *localtime(const time_t *timer), struct tm *gmtime(const time_t *timer)breaks calendar time into local time and UTC★ They return static storage — the next call overwrites it, and they are not thread-safe
localtime_r, gmtime_rstruct tm *localtime_r(const time_t *timer, struct tm *buf), struct tm *gmtime_r(const time_t *timer, struct tm *buf)the same, but you supply the destinationStandardised in C23; before that they were POSIX. Prefer these in new code
localtime_s, gmtime_sthe Annex K versionssame★K (chapter 83)
timegmtime_t timegm(struct tm *timeptr)broken-down time read as UTC to calendar timeC23. The UTC counterpart of mktime
asctime, ctimechar *asctime(const struct tm *timeptr), char *ctime(const time_t *timer)a string in a fixed form★ Better not used — static buffer, and the fixed form cannot follow the locale
asctime_s, ctime_sthe Annex K versionsthey take a buffer and its size★K
strftimesize_t strftime(char * restrict s, size_t maxsize, const char * restrict format, const struct tm * restrict timeptr)characters written, or 0 if there was not room★ Zero means failure — and also an empty result. The format follows LC_TIME (chapter 74)
timespec_getint timespec_get(struct timespec *ts, int base)returns base, or 0 on failureC11, which gave TIME_UTC; C23 added TIME_MONOTONIC, TIME_ACTIVE and TIME_THREAD_ACTIVE
timespec_getresint timespec_getres(struct timespec *ts, int base)that clock’s resolutionC23. It answers “how finely can this be measured”

Table 105.49 — <time.h> reference

NameWhat★trap
time_tcalendar time★ It may be a floating type. Neither meaning nor resolution is fixed
clock_tprocessor timedivide by CLOCKS_PER_SEC
struct tmbroken-down time★ tm_year is the year minus 1900, and tm_mon counts from 0
struct timespecseconds and nanosecondsfilled in by timespec_get
CLOCKS_PER_SECthe divisor turning clock_t into seconds★ Not guaranteed to be 1,000,000
TIME_UTC, TIME_MONOTONIC, TIME_ACTIVE, TIME_THREAD_ACTIVEthe clock timespec_get selectsthe last three are C23
NULL, size_t, errno_t, rsize_tnames from other headersthe last two are ★K

Table 105.50 — Types and macros

<stdlib.h> — the drawer of odds and ends#

Body: chapter 71(the chapter), chapter 46(dynamic memory), chapter 89(allocators).

A drawer, as the name says — memory allocation, ending the program, string to number, sorting and searching, random numbers and multibyte conversion, all in one header. It is easier taken family by family.

NameFormArguments and returnWhat it does · ★trap
mallocvoid *malloc(size_t size)reserves space; null on failure★ The contents are indeterminate. ★ For a size of 0 it gives either null or a unique address — which one is unspecified
callocvoid *calloc(size_t nmemb, size_t size)the same, but zeroed★ The function checks the multiplication for overflow — which makes it the safer choice for arrays
reallocvoid *realloc(void *ptr, size_t size)changes the size; null on failure★★ The original survives a failure — p = realloc(p, n) loses it. ★ In C23 a size of 0 became undefined behaviour
aligned_allocvoid *aligned_alloc(size_t alignment, size_t size)reserves space at a given alignment★ size must be a multiple of alignment
freevoid free(void *ptr)gives it back★ Passing null is safe. ★ Calling it twice is undefined behaviour
free_sized, free_aligned_sizedvoid free_sized(void *ptr, size_t size), void free_aligned_sized(void *ptr, size_t alignment, size_t size)gives it back, stating the sizeC23. It frees the allocator from recording the size — ★ the wrong size is undefined behaviour
memalignmentsize_t memalignment(const void *p)the alignment that address satisfiesC23

Table 105.51 — <stdlib.h> reference — memory allocation

NameFormArguments and returnWhat it does · ★trap
exitvoid exit(int status)normal termination; does not returnruns what atexit registered and flushes the streams. ★ Must not be called from a signal handler
quick_exitvoid quick_exit(int status)quick terminationruns only what at_quick_exit registered — it does not flush streams
_Exitvoid _Exit(int status)immediate termination★ Runs nothing that was registered. The only termination safe in a signal handler
abortvoid abort(void)abnormal terminationraises SIGABRT. ★ Flushing the streams is not guaranteed
atexit, at_quick_exitint atexit(void (*func)(void)), int at_quick_exit(void (*func)(void))registers a function to run at the end; 0 on success★ They run in reverse order of registration. At least 32 can be registered
systemint system(const char *string)hands the string to the command processor★ A null argument asks whether there is one. ★★ Passing user input straight through is command injection
getenvchar *getenv(const char *name)the value, or null★ The string must not be modified, and the next call may overwrite it
getenv_sthe Annex K versionit also reports the length★K (chapter 83)
EXIT_SUCCESS, EXIT_FAILUREmacrosvalues for exit★ Success can be 0 or EXIT_SUCCESS, but the only portable failure value is EXIT_FAILURE

Table 105.52 — <stdlib.h> reference — ending the program

NameFormArguments and returnWhat it does · ★trap
atoi, atol, atofint atoi(const char *nptr) and so onthe value read★★ They cannot report failure. “Zero” and “could not read it” are indistinguishable — not for new code
strtol, strtoullong strtol(const char * restrict nptr, char ** restrict endptr, int base) and so onthe value read; where it stopped comes back through endptr★ On overflow they give LONG_MAX or LONG_MIN and set errno to ERANGE — so clear errno before the call. ★ A base of 0 infers the base from the prefix (0x, 0)
strtod, strtof, strtoldthe floating versionssame★ The decimal point follows LC_NUMERIC — a common way to break a file format (chapter 73)
strtod32, strtod64, strtod128the decimal floating versionssameoptional
strfromd, strfromf, strfromlint strfromd(char * restrict s, size_t n, const char * restrict format, double fp) and so onthe other direction — number to string. Like snprintf it returns the length it wantedC23. ★ Unaffected by the locale, which makes it right for file formats
strfromd32, strfromd64, strfromd128the decimal versionssameoptional

Table 105.53 — <stdlib.h> reference — between strings and numbers

NameFormArguments and returnWhat it does · ★trap
abs, labs, llabsint abs(int j) and so onabsolute value★ The most negative value is not representable — undefined behaviour
div, ldiv, lldivdiv_t div(int numer, int denom) and so onquotient and remainder at oncediv_t, ldiv_t and lldiv_t hold quot and rem
qsortvoid qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))sorts in place★ Not a stable sort. ★ An inconsistent comparison function is undefined behaviour — comparing by subtraction can overflow
bsearchvoid *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))the element, or null★ The array must already be sorted — otherwise undefined behaviour
qsort_s, bsearch_sthe Annex K versionsthey take a context pointer★K better, since the comparison can carry state
rand, srandint rand(void), void srand(unsigned int seed)0 to RAND_MAX★★ Never for cryptography. ★ The quality varies by implementation, and it is not thread-safe
mblen, mbtowc, wctombint mblen(const char *s, size_t n) and so onone character at a time★ State is hidden inside the function — not thread-safe. Use the mbrtowc family in <wchar.h>, which keeps the state outside
mbstowcs, wcstombswhole stringscharacters converted★ Termination is not guaranteed — an exact fit leaves it off
Annex K conversionsmbstowcs_s, wcstombs_s, wctomb_sthe Annex K versions★K
MB_CUR_MAXmacrothe most bytes per character in the current locale★ Not a constant — it changes with the locale
RAND_MAXmacrothe upper bound of randat least 32767

Table 105.54 — <stdlib.h> reference — arithmetic, sorting, randomness, multibyte

NameWhatNote
set_constraint_handler_ssets what runs when a contract is violated★K of type constraint_handler_t
abort_handler_s, ignore_handler_sa handler that ends at once; one that ignores★K the two provided
call_once, ONCE_FLAG_INITre-exposed from <threads.h>
NULL, size_t, wchar_t, errno_t, rsize_tnames from other headersthe last two are ★K

Table 105.55 — Annex K’s constraint handler

<stdio.h> — stream input and output#

Body: chapter 68(streams in practice), chapter 69(the traps of reading and writing), chapter 9(where streams came from).

Everything here sits on one picture: the stream. Open it, read and write, move about, close it. A buffer sits in between, and that alone accounts for half the traps in this header.

NameFormArguments and returnWhat it does · ★trap
fopenFILE *fopen(const char * restrict filename, const char * restrict mode)a stream, or null on failure★ Without "b" it is text mode, where line endings may be translated. ★ The reason for a failure is in errno
freopenFILE *freopen(const char * restrict filename, const char * restrict mode, FILE * restrict stream)reopens an existing stream on another fileused to point stdin or stdout at a file
fcloseint fclose(FILE *stream)closes it; 0 on success, EOF on failure★★ Check the return value — a write that failed while flushing surfaces here for the first time
fflushint fflush(FILE *stream)flushes the buffer★ A null argument flushes every output stream. ★ Calling it on an input stream is undefined behaviour
setbuf, setvbufvoid setbuf(FILE * restrict stream, char * restrict buf), int setvbuf(FILE * restrict stream, char * restrict buf, int mode, size_t size)replaces the buffer★ Must be called before any reading or writing. The modes are _IOFBF (full), _IOLBF (line) and _IONBF (none)
remove, renameint remove(const char *filename), int rename(const char *old, const char *new)deletes and renames; 0 on success★ The effect on an open file is unspecified. ★ Whether rename replaces an existing name is unspecified too
tmpfile, tmpnamFILE *tmpfile(void), char *tmpnam(char *s)a temporary file; a temporary name★★ tmpnam gives you only a name — the gap before you use it is a security hole. Use tmpfile. ★ TMP_MAX bounds how many names can be generated

Table 105.56 — <stdio.h> reference — opening, closing, buffering

NameFormArguments and returnWhat it does · ★trap
fgetc, getc, getcharint fgetc(FILE *stream) and so onone character; EOF at end or on error★★ Store it in an int — a char cannot tell EOF from 0xFF. ★ getc may be a macro and evaluate its argument more than once
fputc, putc, putcharint fputc(int c, FILE *stream) and so onthe character written, or EOF★ putc may be a macro too
ungetcint ungetc(int c, FILE *stream)pushes one character back★ Only one is guaranteed
fgetschar *fgets(char * restrict s, int n, FILE * restrict stream)the string, or null at end★ It keeps the newline. Whether the line was truncated is told by its presence
fputs, putsint fputs(const char * restrict s, FILE * restrict stream), int puts(const char *s)writes★ puts appends a newline; fputs does not
fread, fwritesize_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream) and so onthe number of elements read or written★ Not bytes. When fewer come back, feof and ferror say whether it was the end or an error
the printf familyprintf, fprintf, sprintf, snprintfcharacters written★★ sprintf knows no length — use snprintf. ★ snprintf returns the length it wanted, which is how you detect truncation
the vprintf familyvprintf, vfprintf, vsprintf, vsnprintfthe versions taking a va_list(chapter 63)
the scanf familyscanf, fscanf, sscanfthe number of items assigned★★ A %s without a width overflows. ★ Ignore the return value and you will use variables that were never filled in
the vscanf familyvscanf, vfscanf, vsscanfthe versions taking a va_list

Table 105.57 — <stdio.h> reference — reading and writing

NameFormArguments and returnWhat it does · ★trap
fseek, ftellint fseek(FILE *stream, long offset, int whence), long ftell(FILE *stream)moves and reports the positionwhence is SEEK_SET, SEEK_CUR or SEEK_END. ★ In text mode you may only return to a value ftell gave you. ★ Being long, it is too small for large files
fgetpos, fsetposint fgetpos(FILE * restrict stream, fpos_t * restrict pos), int fsetpos(FILE *stream, const fpos_t *pos)saves and restores a position as an fpos_t★ Use these for large files — they have no long limit
rewindvoid rewind(FILE *stream)returns to the start and clears the error indicator★ It returns nothing — failure cannot be detected
feof, ferror, clearerrint feof(FILE *stream) and so onask and clear the end and error indicators★★ feof becomes true only after a read has failed — while (!feof(f)) is the classic way to process the last line twice
perrorvoid perror(const char *s)writes the message for errno to standard errorprefixed with s

Table 105.58 — <stdio.h> reference — position and state

FamilyNamesNote
streamsstdin, stdout, stderr★ stderr is unbuffered or line-buffered
macrosEOF, BUFSIZ, FILENAME_MAX, FOPEN_MAX, TMP_MAX, SEEK_SET, SEEK_CUR, SEEK_END, NULL, _IOFBF, _IOLBF, _IONBF★ All that is guaranteed of EOF is that it is negative
typesFILE, fpos_t, size_t★ Do not look inside a FILE
Annex Kfopen_s, freopen_s, tmpfile_s, tmpnam_s, gets_s, printf_s, fprintf_s, sprintf_s, snprintf_s, vprintf_s, vfprintf_s, vsprintf_s, vsnprintf_s, scanf_s, fscanf_s, sscanf_s, vscanf_s, vfscanf_s, vsscanf_s, TMP_MAX_S, errno_t, rsize_t★K gets was removed in C11 and gets_s took its place (chapter 83)

Table 105.59 — Macros, types and Annex K

<math.h> — the mathematical functions#

Body: chapter 78(the chapter), chapter 52(the mathematics of approximation), chapter 7(representing numbers).

The header carries more than a hundred and sixty names, and yet there is little to memorise. Three rules cover it.

RuleMeaningExample
suffix f, lthe float and long double versionssqrtf, sqrtl
<tgmath.h>a macro that picks the suffix for youone sqrt(x) for all three
decimal namesanything with d32, d64 or d128 is for decimal floating pointoptional, and often absent

Table 105.60 — How to read the names

NameWhat it asks★trap
fpclassifyone of FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL
isnan, isinf, isfinite, isnormalNaN, infinite, finite, normal★ Use isnan rather than x != x
issubnormal, iszero, iscanonical, issignalingsubnormal, zero, canonical, signalling NaNC23
signbitwhether the sign bit is set★ True for -0.0 — which x < 0 is not
isgreater, isgreaterequal, isless, islessequal, islessgreater, isunorderedcompare without raising an exception on NaN★ Plain > and < raise on a signalling NaN
iseqsigtests equality but raises on NaNC23
totalorder, totalordermagcompare using the IEEE 754 total orderC23. It even separates -0.0 from +0.0

Table 105.61 — Asking what a value is — these are macros

FamilyNamesNote · ★trap
trigonometricsin, cos, tan, asin, acos, atan, atan2★ atan2 resolves the quadrant — the argument order is (y, x)
multiples of 𝜋sinpi, cospi, tanpi, asinpi, acospi, atanpi, atan2piC23. The argument is taken as a multiple of 𝜋, which is more accurate
hyperbolicsinh, cosh, tanh, asinh, acosh, atanh
exponentialexp, exp2, exp10, expm1, exp2m1, exp10m1★ expm1 computes 𝑒𝑥−1 accurately for small x
logarithmiclog, log2, log10, log1p, logp1, log2p1, log10p1, logb, ilogb, llogb★ log1p is the accurate form of log(1+𝑥)
powerspow, pown, powr, rootn, compoundn, sqrt, rsqrt, cbrt, hypot★ hypot finds the hypotenuse without overflowing in between
error and gammaerf, erfc, lgamma, tgamma★ lgamma is the logarithm of the gamma function

Table 105.62 — The elementary functions

FamilyNamesNote · ★trap
roundingceil, floor, trunc, round, roundeven, nearbyint, rint, lrint, llrint, lround, llround★ rint follows the current rounding direction and may raise; nearbyint does not
to an integerfromfp, ufromfp, fromfpx, ufromfpxC23. You choose the direction and the width
remaindersfmod, remainder, remquo★ fmod and remainder differ in sign
scalingldexp, scalbn, scalbln, frexp, modf★ frexp and modf return the other half through a pointer argument
maximum and minimumfmax, fmin, fdim, fmaximum, fminimum, fmaximum_num, fminimum_num, fmaximum_mag, fminimum_mag, fmaximum_mag_num, fminimum_mag_num★ fmax ignores a NaN while C23′s fmaximum propagates it — they are different functions
sign and neighboursfabs, copysign, nextafter, nexttoward, nextup, nextdown★ nextafter gives the very next representable value
making NaNsnan, getpayload, setpayload, setpayloadsig, canonicalizeC23 opened a way to work with a NaN’s payload

Table 105.63 — Rounding, remainders, moving the exponent

FamilyNamesNote
multiply and addfma★ It rounds the multiplication and addition only once — the heart of precision
float resultfadd, fsub, fmul, fdiv, fsqrt, ffmaC23. Computed in a wider type, rounded once to float
double resultdaddl, dsubl, dmull, ddivl, dsqrtl, dfmalcomputed in long double, rounded to double
decimal versionsd32addd64, d32addd128, d64addd128, d32subd64, d32subd128, d64subd128, d32muld64, d32muld128, d64muld128, d32divd64, d32divd128, d64divd128, d32sqrtd64, d32sqrtd128, d64sqrtd128, d32fmad64, d32fmad128, d64fmad128the same for decimal floating point

Table 105.64 — Keeping precision — computed wide, rounded once

FamilyNamesNote
quantumquantized32, quantized64, quantized128, quantumd32, quantumd64, quantumd128, samequantumd32, samequantumd64, samequantumd128, llquantexpd32, llquantexpd64, llquantexpd128in decimal, the same value can be held at different quanta — these work with that
encodingencodedecd32, encodedecd64, encodedecd128, decodedecd32, decodedecd64, decodedecd128, encodebind32, encodebind64, encodebind128, decodebind32, decodebind64, decodebind128move between the decimal and binary encodings

Table 105.65 — Decimal floating point only

★ There are two ways errors are reported — errno (EDOM, ERANGE) and the floating-point exceptions. Which one is in use is told by math_errhandling (MATH_ERRNO, MATH_ERREXCEPT). HUGE_VAL, HUGE_VALF and HUGE_VALL are what overflow returns, and INFINITY and NAN come from <float.h>.