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.
| Column | What is in it |
|---|---|
| Name | The function’s name. Where f/l variants exist they share one cell |
| Form | The 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 return | What each parameter is, what comes back, and how failure is reported |
| What it does · ★traps | A 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*)#
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
memcpy | void *memcpy(void *restrict s1, const void *restrict s2, size_t n) | s1 destination, s2 source, n bytes. Returns s1 | Moves n bytes. ★ If the regions overlap it is outside the contract — that is what restrict promises. If they may overlap, use memmove |
memmove | void *memmove(void *s1, const void *s2, size_t n) | The same. Returns s1 | Moves correctly even when overlapping. No trap — if in doubt, use this |
memcmp | int memcmp(const void *s1, const void *s2, size_t n) | Two regions and a length. Returns negative, 0 or positive | Compares bytes in order. ★ Do not compare whole structs — padding gets into the value (chapter 48) |
memchr | QVoid *memchr(QVoid *s, int c, size_t n) | c is converted to unsigned char. Null if not found | Searches forward within n bytes. Unlike the string functions it does not stop at a NUL |
memset | void *memset(void *s, int c, size_t n) | c converted to unsigned char. Returns s | Fills 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_explicit | void *memset_explicit(void *s, int c, size_t n) | As memset | C23. A wipe the optimizer may not remove — for clearing a password just before freeing |
memccpy | void *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 met | Arrived in C23 (an old POSIX function). Does “copy up to the delimiter” in one step |
memcpy_s | errno_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_s | errno_t memmove_s(void *s1, rsize_t s1max, const void *s2, rsize_t n) | The same | ★K The same story |
memset_s | errno_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)#
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
strcpy | char *strcpy(char *restrict s1, const char *restrict s2) | Returns s1 | Copies through the NUL. ★ It does not know the destination’s size — the classic overflow |
strncpy | char *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 |
strcat | char *strcat(char *restrict s1, const char *restrict s2) | Returns s1 | Appends. ★ It does not know the size, and it finds the end again every time — repeated in a loop it becomes quadratic |
strncat | char *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 |
strdup | char *strdup(const char *s) | Null on failure | Arrived in C23. You must free it — ownership comes to you (chapter 94) |
strndup | char *strndup(const char *s, size_t n) | At most n bytes. Null on failure | C23. Stops at n even if no end is found |
strcpy_s | errno_t strcpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2) | 0 on success | ★K Chapter 83 |
strncpy_s | errno_t strncpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n) | 0 on success | ★K Chapter 83 |
strcat_s | errno_t strcat_s(char *restrict s1, rsize_t s1max, const char *restrict s2) | 0 on success | ★K Chapter 83 |
strncat_s | errno_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#
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
strlen | size_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) |
strcmp | int strcmp(const char *s1, const char *s2) | Negative, 0 or positive | ★ Not “dictionary order” but order by unsigned char value. Human ordering is strcoll |
strncmp | int strncmp(const char *s1, const char *s2, size_t n) | The same | Compares the first n bytes. Used for prefix tests |
strcoll | int strcoll(const char *s1, const char *s2) | The same | Compares in the order the locale prescribes (chapter 74). Slow — for repeated comparison use strxfrm |
strxfrm | size_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 unspecified | Freezes a locale comparison into a “key”. Keys can then be compared with strcmp |
strnlen_s | size_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#
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
strchr | QChar *strchr(QChar *s, int c) | Null if not found. If c is '\0' it points at the terminating NUL | Finds one byte, searching forward. ★ In a multibyte encoding it can land inside a character (chapter 77) |
strrchr | QChar *strrchr(QChar *s, int c) | The same | Searches backward. Used to find the last separator in a path — ★ with the same danger |
strstr | QChar *strstr(QChar *s1, const char *s2) | Null if not found; s1 if s2 is empty | Finds a substring. The standard prescribes no algorithm — it may be O(nm) in the worst case |
strspn | size_t strspn(const char *s1, const char *s2) | A length | How long the prefix made only of characters from s2 is. Used for skipping |
strcspn | size_t strcspn(const char *s1, const char *s2) | A length | The reverse — how far until a character from s2 appears |
strpbrk | QChar *strpbrk(QChar *s1, const char *s2) | Null if not found | The first place any character of s2 occurs |
strtok | char *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_s | char *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#
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
strerror | char *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_s | size_t strerrorlen_s(errno_t errnum) | The length needed | ★K Pairs with strerror_s |
Table 105.6 — <string.h> reference — error strings
| Macro or type | What it is | Note |
|---|---|---|
NULL | The null pointer constant | From C23 there is nullptr (chapters 37 and 87) |
size_t | The unsigned type of sizes and counts | Its home is <stddef.h> (chapter 36) |
rsize_t | ★K Annex K’s size type | Bounded by RSIZE_MAX |
errno_t | ★K Annex K’s error type | Effectively 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 function | What it is |
|---|---|
| Argument | A value representable as unsigned char, or EOF. ★ Anything else is outside the contract |
| ★ The commonest accident | Passing 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) |
| Return | The classifying functions return “nonzero if true”, 0 if false. Do not assume 1 |
| Locale | All but isdigit and isxdigit can be changed by LC_CTYPE (chapter 73) |
Table 105.8 — What holds for every function
| Name | True for | Note · ★traps |
|---|---|---|
isalnum | A letter or a digit | isalpha or isdigit |
isalpha | A letter | ★ Not “A–Z, a–z” — the locale and the character set decide (chapter 8′s EBCDIC) |
isblank | A word separator — space and horizontal tab | C99. Means “blank within a line” |
iscntrl | A control character | Not drawn on screen |
isdigit | 0–9 | ★ Independent of the locale — the standard fixes these ten |
isgraph | A printing character other than space | isprint minus the space |
islower | A lowercase letter | The locale decides |
isprint | A printing character, space included | |
ispunct | A printing character that is neither letter, digit nor space | |
isspace | Whitespace — space, \\n, \\t, \\v, \\f, \\r | Used for skipping input |
isupper | An uppercase letter | The locale decides |
isxdigit | A hexadecimal digit | ★ Independent of the locale |
tolower | Returns 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) |
toupper | The 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.
| Name | Form | Arguments and return | What it does · ★traps |
|---|---|---|---|
ckd_add | bool 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_sub | bool ckd_sub(type1 *result, type2 a, type3 b) | The same | Subtraction. Also catches going below 0 in an unsigned type |
ckd_mul | bool ckd_mul(type1 *result, type2 a, type3 b) | The same | Multiplication. ★ 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 contract | What it says | Note |
|---|---|---|
| Accuracy of the result | If it did not overflow, the mathematically correct value | Not “the wrapped value” |
| When it overflowed | result receives the wrapped value | Not undefined behaviour — the value is settled |
| Operands | Integer types other than bool and the bit-precise integers | char 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
assert | void assert(scalar expression) | takes one expression; returns nothing | prints 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 |
NDEBUG | macro | only whether it is defined matters, not its value | when 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
errno | a modifiable lvalue written as int errno | can 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 |
EDOM | integer constant expression | distinct non-zero values | domain error — the argument is not mathematically allowed, as in sqrt(-1.0) (chapter 78) |
ERANGE | integer constant expression | same | the value is outside the representable range — overflow in strtol (chapter 71), divergence in exp |
EILSEQ | integer constant expression | same | the byte sequence is not a valid character in that encoding — multibyte conversion (chapter 75) |
errno_t | type | the 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
setjmp | int 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 |
longjmp | void 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_buf | array type | what 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
va_start | void 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_arg | type 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_copy | void va_copy(va_list dest, va_list src) | copies the current state of src into dest | C99. 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_end | void 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_list | type | holds 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.
| Name | Form | What it is | What it does · ★trap |
|---|---|---|---|
size_t | unsigned integer type | the type sizeof yields | holds sizes and counts. ★ It is unsigned — a subtraction that would go negative wraps to an enormous value instead (chapter 6) |
ptrdiff_t | signed integer type | the type of the difference of two pointers | ★ The contract covers only two places within the same array (chapter 38) |
wchar_t | integer type | the 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_t | object type | the type with the strictest fundamental alignment | the yardstick that the address returned by malloc satisfies (chapter 4) |
nullptr_t | type | the type of nullptr | C23. ★ A type with exactly one value — nullptr itself (chapter 87) |
rsize_t | the same as size_t | a name used by Annex K | ★K optional, so it may be absent (chapter 83) |
NULL | macro 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) |
offsetof | size_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.
| Header | What it used to give | Now |
|---|---|---|
<stdbool.h> | bool, true, false as macros | all three are keywords; including it is optional |
<stdalign.h> | alignas and alignof as macros | both 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.
| Macro | Expands to | Macro | Expands 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.
| Suffix | What | Example |
|---|---|---|
_MIN | the smallest value the type holds | INT_MIN |
_MAX | the largest | INT_MAX |
_WIDTH | the bit width, sign bit included | INT_WIDTH — added by C23 |
Table 105.19 — How to read the names
★ Unsigned types have no _MIN: it is zero.
| Type | Minimum | Maximum | Width · ★trap |
|---|---|---|---|
char | CHAR_MIN | CHAR_MAX | CHAR_WIDTH. ★ Whether it is signed is up to the implementation, so CHAR_MIN may be 0 |
signed char | SCHAR_MIN | SCHAR_MAX | SCHAR_WIDTH |
unsigned char | 0 | UCHAR_MAX | UCHAR_WIDTH |
short | SHRT_MIN | SHRT_MAX | SHRT_WIDTH |
unsigned short | 0 | USHRT_MAX | USHRT_WIDTH |
int | INT_MIN | INT_MAX | INT_WIDTH |
unsigned int | 0 | UINT_MAX | UINT_WIDTH |
long | LONG_MIN | LONG_MAX | LONG_WIDTH. ★ Eight bytes on 64-bit Linux, four on Windows |
unsigned long | 0 | ULONG_MAX | ULONG_WIDTH |
long long | LLONG_MIN | LLONG_MAX | LLONG_WIDTH |
unsigned long long | 0 | ULLONG_MAX | ULLONG_WIDTH |
bool | 0 | BOOL_MAX | BOOL_WIDTH. Added by C23 — each is 1 |
Table 105.20 — <limits.h> entry by entry
| Name | What | ★trap |
|---|---|---|
CHAR_BIT | bits in a byte | ★ The standard does not promise 8. In practice no machine in use today says otherwise (chapter 6) |
MB_LEN_MAX | the most bytes one multibyte character can take in any locale | different from MB_CUR_MAX, which is the current locale’s value (chapter 75) |
BITINT_MAXWIDTH | the 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).
| Suffix | What | Names | ★trap |
|---|---|---|---|
_MANT_DIG | digits in the significand, in base FLT_RADIX | FLT_MANT_DIG, DBL_MANT_DIG, LDBL_MANT_DIG | this is where precision comes from |
_DIG | decimal digits that survive a round trip | FLT_DIG, DBL_DIG, LDBL_DIG | usually 15 for double |
_DECIMAL_DIG | digits needed to write the value out and read it back unchanged | FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG | ★ Not the same as _DIG — this one is larger (17 for double) |
_EPSILON | the gap between 1 and the next larger value | FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON | ★ It is not “a small enough number” — using it directly to compare large values is wrong |
_MIN | the smallest normalised positive value | FLT_MIN, DBL_MIN, LDBL_MIN | ★ Not the smallest positive value — that is _TRUE_MIN |
_TRUE_MIN | the smallest positive value, subnormals included | FLT_TRUE_MIN, DBL_TRUE_MIN, LDBL_TRUE_MIN | equals _MIN where there are no subnormals |
_MAX | the largest finite value | FLT_MAX, DBL_MAX, LDBL_MAX | beyond it lies infinity |
_NORM_MAX | the largest normalised finite value | FLT_NORM_MAX, DBL_NORM_MAX, LDBL_NORM_MAX | equals _MAX in binary formats |
_MIN_EXP, _MAX_EXP | exponent range in base FLT_RADIX | FLT_MIN_EXP, DBL_MIN_EXP, LDBL_MIN_EXP / FLT_MAX_EXP, DBL_MAX_EXP, LDBL_MAX_EXP | |
_MIN_10_EXP, _MAX_10_EXP | exponent range in decimal | FLT_MIN_10_EXP, DBL_MIN_10_EXP, LDBL_MIN_10_EXP / FLT_MAX_10_EXP, DBL_MAX_10_EXP, LDBL_MAX_10_EXP | |
_HAS_SUBNORM | whether subnormals exist | FLT_HAS_SUBNORM, DBL_HAS_SUBNORM, LDBL_HAS_SUBNORM | one of 1, 0 or (unknown) |
_IS_IEC_60559 | whether it follows IEC 60559 (IEEE 754) | FLT_IS_IEC_60559, DBL_IS_IEC_60559, LDBL_IS_IEC_60559 | added by C23 |
_SNAN | a signalling NaN | FLT_SNAN, DBL_SNAN, LDBL_SNAN | C23. Present when the type has one |
Table 105.22 — What each suffix means — all three prefixes take them
| Name | What | ★trap |
|---|---|---|
FLT_RADIX | the base of the exponent | ★ Despite the FLT_ prefix it applies to all three types. In practice it is 2 |
FLT_ROUNDS | the current rounding direction | ★ Not a constant — it can change while the program runs (fesetround, chapter 78) |
FLT_EVAL_METHOD | the width intermediate results are computed in | ★ It means arithmetic on float may be carried out in double |
DECIMAL_DIG | the _DECIMAL_DIG of the widest type | superseded in C23 — use LDBL_DECIMAL_DIG |
CR_DECIMAL_DIG | digits for correctly rounded decimal conversion | C23 |
INFINITY | float infinity | defined only where it exists |
NAN | a 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.
| Form | Promise | ★trap |
|---|---|---|
intN_t, uintN_t | exactly N bits, no padding, two’s complement | ★ Not guaranteed to exist — undefined on a machine without that width |
int_leastN_t, uint_leastN_t | the smallest type with at least N bits | ★ These always exist. The most portable choice |
int_fastN_t, uint_fastN_t | at 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
| Name | What | Companions | ★trap |
|---|---|---|---|
intmax_t, uintmax_t | the widest integer types | INTMAX_MIN, INTMAX_MAX, INTMAX_WIDTH, UINTMAX_MAX, UINTMAX_WIDTH | ★ _BitInt does not take part in this |
intptr_t, uintptr_t | an integer a pointer can be put in and taken back out of | INTPTR_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 width | intN_t, uintN_t | INTN_MIN, INTN_MAX, INTN_WIDTH, UINTN_MAX, UINTN_WIDTH | N is 8, 16, 32 or 64 |
| at least N bits | int_leastN_t, uint_leastN_t | INT_LEASTN_MIN, INT_LEASTN_MAX, INT_LEASTN_WIDTH, UINT_LEASTN_MAX, UINT_LEASTN_WIDTH | |
| the fast ones | int_fastN_t, uint_fastN_t | INT_FASTN_MIN, INT_FASTN_MAX, INT_FASTN_WIDTH, UINT_FASTN_MAX, UINT_FASTN_WIDTH | |
| writing constants | makes a constant of that type | INTN_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
| Name | Limit of what | Note |
|---|---|---|
SIZE_MAX, SIZE_WIDTH | size_t | the ceiling when computing an allocation size |
PTRDIFF_MIN, PTRDIFF_MAX | ptrdiff_t | |
WCHAR_MIN, WCHAR_MAX, WCHAR_WIDTH | wchar_t | (chapter 75) |
WINT_MIN, WINT_MAX, WINT_WIDTH | wint_t | must be able to hold WEOF |
SIG_ATOMIC_MIN, SIG_ATOMIC_MAX, SIG_ATOMIC_WIDTH | sig_atomic_t | the only type a signal handler may touch (chapter 80) |
RSIZE_MAX | where 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
imaxabs | intmax_t imaxabs(intmax_t j) | the absolute value | ★ The absolute value of the most negative number is not representable — undefined behaviour |
imaxdiv | imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom) | quotient and remainder together | imaxdiv_t is a struct with quot and rem |
strtoimax | intmax_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) |
strtoumax | uintmax_t strtoumax(const char * restrict nptr, char ** restrict endptr, int base) | same | ★ Unsigned, yet it accepts - and gives you the wrapped value |
wcstoimax, wcstoumax | the wide-string versions | same | (chapter 75) |
intmax_t, uintmax_t, wchar_t | types | re-exposed from <stdint.h> and <stddef.h> |
Table 105.27 — <inttypes.h> entry by entry
| Form | What | Example |
|---|---|---|
PRIBN | format for printing an exact-width type — B stands for d, i, o, u or x | PRId32, PRIu64 |
PRIBLEASTN, PRIBFASTN | formats for the least and fast types | PRIdLEAST16, PRIuFAST32 |
PRIBMAX, PRIBPTR | formats for intmax_t and intptr_t | PRIdMAX, PRIdPTR |
PRIXN, PRIXLEASTN, PRIXFASTN, PRIXMAX, PRIXPTR | the uppercase hexadecimal versions of the same | PRIX64 |
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.
| Name | What it counts | ★trap · use |
|---|---|---|
stdc_leading_zeros | zero bits at the front | it depends on the width, so the type matters |
stdc_leading_ones | one bits at the front | |
stdc_trailing_zeros | zero bits at the back | tells you what power of two divides the value |
stdc_trailing_ones | one bits at the back | |
stdc_first_leading_zero, stdc_first_leading_one | the 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_one | the first such position from the back | same |
stdc_count_zeros, stdc_count_ones | how many bits are zero, how many are one | stdc_count_ones is the population count |
stdc_has_single_bit | whether exactly one bit is set | the power-of-two test — ★ false for 0 |
stdc_bit_width | the fewest bits that hold the value | stdc_bit_width(0) is 0 |
stdc_bit_floor, stdc_bit_ceil | the 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
setlocale | char *setlocale(int category, const char *locale) | takes a category and a name, returns the current locale name; null on failure | A 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 |
localeconv | struct 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_ALL | category | everything | ★ Switching it wholesale to something other than "C" changes even the decimal point printf writes — a common way to break a file format |
LC_COLLATE | category | collation order | what strcoll and strxfrm consult |
LC_CTYPE | category | character classes and case | what <ctype.h> and multibyte conversion consult |
LC_MONETARY | category | monetary format | read it through localeconv and format it yourself |
LC_NUMERIC | category | decimal point and grouping | ★ printf and strtod consult this |
LC_TIME | category | date and time format | what strftime consults |
NULL | macro | the 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).
| Name | What is true · what it does | Note · ★trap |
|---|---|---|
iswalnum | a letter or a digit | same meaning as its <ctype.h> counterpart |
iswalpha | a letter | the locale decides |
iswblank | a blank | C99 |
iswcntrl | a control character | |
iswdigit | 0–9 | ★ independent of the locale |
iswgraph | printing, space excluded | |
iswlower | lowercase | |
iswprint | printing | |
iswpunct | punctuation | |
iswspace | whitespace | |
iswupper | uppercase | |
iswxdigit | a hexadecimal digit | ★ independent of the locale |
towlower, towupper | the corresponding case, or unchanged | ★ The one-character-to-one-character limit is still there |
wctype | turns a class name such as "alpha" into a wctype_t | zero for an unknown name |
iswctype | whether the character is in that class | locale-defined classes work too |
wctrans | turns a mapping name such as "tolower" into a wctrans_t | zero for an unknown name |
towctrans | applies the mapping wctrans returned | |
wint_t | a type holding a wide character or WEOF | ★ Not wchar_t — WEOF has to fit |
WEOF | the wint_t value meaning end of input | ★ Not guaranteed to be -1 |
wctype_t, wctrans_t | handles 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
mbrtoc8 | size_t mbrtoc8(char8_t * restrict pc8, const char * restrict s, size_t n, mbstate_t * restrict ps) | bytes consumed; special values report the situation | C23. ★ It may yield one UTF-8 byte at a time, so it has to be called repeatedly |
c8rtomb | size_t c8rtomb(char *s, char8_t c8, mbstate_t *ps) | bytes written | C23. The other direction |
mbrtoc16 | size_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 |
c16rtomb | size_t c16rtomb(char *s, char16_t c16, mbstate_t *ps) | bytes written | the other direction |
mbrtoc32 | size_t mbrtoc32(char32_t * restrict pc32, const char * restrict s, size_t n, mbstate_t * restrict ps) | same | one code point per call — the easiest of the three to work with |
c32rtomb | size_t c32rtomb(char *s, char32_t c32, mbstate_t *ps) | bytes written | the other direction |
char8_t, char16_t, char32_t | types | code units of UTF-8, UTF-16 and UTF-32 | ★ The widths are fixed, but char8_t arrived in C23 |
mbstate_t | type | the state a conversion carries | ★ Zero it once and keep passing the same one — a fresh one per string |
size_t | type | the 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
signal | void (*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 |
raise | int raise(int sig) | sends a signal to itself; 0 on success | this is what abort does with SIGABRT |
sig_atomic_t | integer type | the 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_IGN | values passed to signal | default action; ignore | |
SIG_ERR | the failure return of signal | ★ It is not null — compare against it explicitly | |
SIGABRT | abnormal termination | raised by abort | |
SIGFPE | an erroneous arithmetic operation | division by zero and the like | ★ Despite the name it also arises in integer division |
SIGILL | an invalid instruction | ||
SIGINT | an interactive attention request | usually Ctrl-C | |
SIGSEGV | an invalid access to storage | ★ Trying to “recover” here is almost always a mistake | |
SIGTERM | a termination request | a 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.
| Family | Names | Meaning |
|---|---|---|
| exception flags | FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW | division by zero, inexact, invalid operation, overflow, underflow |
| all of them | FE_ALL_EXCEPT | the bitwise union of the above |
| rounding directions | FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD, FE_DOWNWARD, FE_TONEARESTFROMZERO | to nearest (the default), toward zero, up, down, ties away from zero |
| default environment and mode | FE_DFL_ENV, FE_DFL_MODE, FE_DYNAMIC | the environment at startup, the default mode, determined at run time |
| decimal | FE_DEC_TONEAREST, FE_DEC_TOWARDZERO, FE_DEC_UPWARD, FE_DEC_DOWNWARD, FE_DEC_TONEARESTFROMZERO | the same for decimal floating point |
| pragmas | FENV_ACCESS, FENV_ROUND, FENV_DEC_ROUND, STDC | used as #pragma STDC … |
| other | FE_SNANS_ALWAYS_SIGNAL | whether signalling NaNs always signal |
Table 105.34 — Exception flags and rounding directions
| Name | What it does | Note · ★trap |
|---|---|---|
feclearexcept | clears flags | ★ The contract is to clear before you measure |
fetestexcept | asks which flags are raised | returns the union of those asked about |
feraiseexcept, fesetexcept | raises flags — signalling, and quietly | fesetexcept is C23 |
fegetexceptflag, fesetexceptflag | saves flag state in a fexcept_t and restores it | |
fetestexceptflag | asks about a saved state | C23 |
fegetround, fesetround | reads and sets the rounding direction | FLT_ROUNDS reflects it |
fegetmode, fesetmode | reads and sets the whole mode as a femode_t | C23 |
fegetenv, fesetenv | reads and sets the whole environment as a fenv_t | |
feholdexcept | saves the environment, clears flags, goes quiet | the opening half of a wrapped computation |
feupdateenv | restores the saved environment and re-raises what happened meanwhile | the closing half |
fe_dec_getround, fe_dec_setround | rounding direction for decimal floating point | C23 |
fenv_t, fexcept_t, femode_t | types 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 type | What is chosen | Example |
|---|---|---|
float | the f-suffixed one | sqrt(x) → sqrtf |
double, integers | the unsuffixed one | sqrt(x) → sqrt — ★ integers are promoted to double |
long double | the l-suffixed one | sqrt(x) → sqrtl |
| complex | the c-prefixed one | sqrt(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).
| Name | What it returns | ★trap |
|---|---|---|
creal | the real part | |
cimag | the imaginary part | |
carg | the argument — the angle in the complex plane | the range is to |
cabs | the absolute value — distance from the origin | ★ Built so that the intermediate computation does not overflow |
conj | the complex conjugate | flips the sign of the imaginary part |
cproj | projection onto the Riemann sphere | gathers the infinities into one |
Table 105.37 — The ones that take a value apart
| Family | Names | Note |
|---|---|---|
| exponential and logarithm | cexp, clog, cpow, csqrt | ★ clog and csqrt have branch cuts: on the negative real axis the answer depends on the sign of zero |
| trigonometric | csin, ccos, ctan | |
| inverse trigonometric | casin, cacos, catan | they have branch cuts |
| hyperbolic | csinh, ccosh, ctanh | |
| inverse hyperbolic | casinh, cacosh, catanh | they have branch cuts |
Table 105.38 — Those that pair with <math.h>
| Name | What | ★trap |
|---|---|---|
CMPLX, CMPLXF, CMPLXL | build 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_RANGE | turned on with #pragma STDC CX_LIMITED_RANGE ON | it says the slower overflow-avoiding formulas for multiplication and division may be skipped |
STDC | the 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).
| Name | What it does | Note · ★trap |
|---|---|---|
thrd_create | creates a thread and runs a function in it | the function’s form is thrd_start_t — int (*)(void *) |
thrd_join | waits for it to finish and takes its result | ★ Join it or detach it — one of the two must happen |
thrd_detach | lets it clean itself up when it ends | ★ A detached thread cannot be joined |
thrd_exit | ends the current thread | the tss destructors run |
thrd_current | a handle to the current thread | |
thrd_equal | whether two handles are the same thread | ★ Do not compare with == — the contents of a thrd_t are unspecified |
thrd_sleep | sleeps for a given duration | it can hand back the remaining time |
thrd_yield | gives up its turn |
Table 105.40 — Threads themselves — thrd_
| Name | What it does | Note · ★trap |
|---|---|---|
mtx_init, mtx_destroy | creates and destroys a mutex | pick mtx_plain, mtx_timed or mtx_recursive |
mtx_lock, mtx_unlock | locks and unlocks | ★ The thread that locked is the one that unlocks |
mtx_trylock | locks if it can, returns at once if it cannot | |
mtx_timedlock | waits only until a given time | only for one made mtx_timed |
cnd_init, cnd_destroy | creates and destroys a condition variable | |
cnd_wait, cnd_timedwait | releases 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_broadcast | wakes one, wakes all | |
call_once | runs exactly once however many threads call it | give it a once_flag set to ONCE_FLAG_INIT |
Table 105.41 — Getting along — mtx_, cnd_, call_once
| Name | What | Note |
|---|---|---|
tss_create, tss_delete | creates and deletes a key | a destructor comes with it — tss_dtor_t |
tss_get, tss_set | reads and writes this thread’s value | ★ TSS_DTOR_ITERATIONS bounds how many times destructors run |
thrd_t, mtx_t, cnd_t, tss_t | the handle types | do not look inside them |
thrd_start_t, tss_dtor_t | function 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.
| Name | What it does | ★trap |
|---|---|---|
atomic_init | gives an atomic object its first value | ★ This is not itself atomic — do it before anyone else can see the object |
atomic_load, atomic_load_explicit | reads | |
atomic_store, atomic_store_explicit | writes | |
atomic_exchange, atomic_exchange_explicit | replaces and returns the old value | |
atomic_compare_exchange_strong, atomic_compare_exchange_strong_explicit | replaces 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_explicit | the same, but may fail for no reason | so it is used inside a loop — and it is faster |
atomic_fetch_key, atomic_fetch_key_explicit | key stands for add, sub, or, xor or and | returns the old value |
atomic_flag_test_and_set, atomic_flag_test_and_set_explicit | sets the flag and returns its previous state | ★ atomic_flag is the one type that is always lock-free |
atomic_flag_clear, atomic_flag_clear_explicit | clears the flag | initialise it with ATOMIC_FLAG_INIT |
atomic_is_lock_free | whether that type is lock-free | ★ The per-type ATOMIC_…_LOCK_FREE macros can answer at compile time |
atomic_thread_fence, atomic_signal_fence | raise an ordering fence — between threads, and against a signal handler | |
kill_dependency | breaks a dependency chain | it goes with memory_order_consume, which is rarely used in practice |
Table 105.43 — The operations of <stdatomic.h>
| Family | Names | Note |
|---|---|---|
| characters | atomic_char8_t, atomic_char16_t, atomic_char32_t, atomic_wchar_t | |
| fixed width | atomic_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 ones | atomic_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 rest | atomic_intmax_t, atomic_uintmax_t, atomic_intptr_t, atomic_uintptr_t, atomic_size_t, atomic_ptrdiff_t | writing _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.
| Family | Names | Note · ★trap |
|---|---|---|
| length | wcslen | ★ Code units, not characters — they differ where wchar_t is UTF-16 |
| copying | wcscpy, wcsncpy, wmemcpy, wmemmove | ★ wcsncpy inherits every trap of strncpy, terminator included |
| appending | wcscat, wcsncat | |
| comparing | wcscmp, wcsncmp, wmemcmp, wcscoll, wcsxfrm | wcscoll and wcsxfrm follow the locale’s order (chapter 74) |
| searching | wcschr, wcsrchr, wcsstr, wcspbrk, wcsspn, wcscspn, wmemchr | |
| splitting | wcstok | ★ You hold the state yourself — unlike strtok it takes a third argument |
| filling | wmemset | |
| time formatting | wcsftime | the wide version of strftime |
Table 105.45 — Strings and memory — the <string.h> counterparts
| Family | Names | Note · ★trap |
|---|---|---|
| single character | btowc, wctob | ★ Meaningful only for characters that are a single byte |
| carrying state | mbrtowc, wcrtomb, mbrlen, mbsinit | ★ Zero an mbstate_t and keep passing the same one |
| whole strings | mbsrtowcs, wcsrtombs | ★ They update the source pointer so conversion can be resumed |
| to numbers | wcstol, wcstoul, wcstod, wcstof, wcstold | the contract of the strtol family (chapter 71) |
| decimal floating point | wcstod32, wcstod64, wcstod128 | optional |
Table 105.46 — Conversion — between bytes and wide, and to numbers
| Family | Names | Note · ★trap |
|---|---|---|
| one character | fgetwc, getwc, getwchar, fputwc, putwc, putwchar, ungetwc | the end is WEOF |
| one line | fgetws, fputws | |
| formatted output | wprintf, fwprintf, swprintf, vwprintf, vfwprintf, vswprintf | ★ swprintf takes a size, like snprintf |
| formatted input | wscanf, fwscanf, swscanf, vwscanf, vfwscanf, vswscanf | |
| choosing the width | fwide | ★ 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
| Family | Names | Note |
|---|---|---|
| types | wchar_t, wint_t, mbstate_t, size_t, FILE | re-exposed from other headers |
| macros | WEOF, WCHAR_MIN, WCHAR_MAX, NULL | |
| Annex K | wcscpy_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).
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
time | time_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 |
difftime | double difftime(time_t time1, time_t time0) | the difference in seconds | ★ Do not compute it by subtraction — time_t need not be in seconds |
clock | clock_t clock(void) | processor time, or (clock_t)-1 | ★ Not wall-clock time. Divide by CLOCKS_PER_SEC for seconds. ★ It can wrap |
mktime | time_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, gmtime | struct 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_r | struct 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 destination | Standardised in C23; before that they were POSIX. Prefer these in new code |
localtime_s, gmtime_s | the Annex K versions | same | ★K (chapter 83) |
timegm | time_t timegm(struct tm *timeptr) | broken-down time read as UTC to calendar time | C23. The UTC counterpart of mktime |
asctime, ctime | char *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_s | the Annex K versions | they take a buffer and its size | ★K |
strftime | size_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_get | int timespec_get(struct timespec *ts, int base) | returns base, or 0 on failure | C11, which gave TIME_UTC; C23 added TIME_MONOTONIC, TIME_ACTIVE and TIME_THREAD_ACTIVE |
timespec_getres | int timespec_getres(struct timespec *ts, int base) | that clock’s resolution | C23. It answers “how finely can this be measured” |
Table 105.49 — <time.h> reference
| Name | What | ★trap |
|---|---|---|
time_t | calendar time | ★ It may be a floating type. Neither meaning nor resolution is fixed |
clock_t | processor time | divide by CLOCKS_PER_SEC |
struct tm | broken-down time | ★ tm_year is the year minus 1900, and tm_mon counts from 0 |
struct timespec | seconds and nanoseconds | filled in by timespec_get |
CLOCKS_PER_SEC | the divisor turning clock_t into seconds | ★ Not guaranteed to be 1,000,000 |
TIME_UTC, TIME_MONOTONIC, TIME_ACTIVE, TIME_THREAD_ACTIVE | the clock timespec_get selects | the last three are C23 |
NULL, size_t, errno_t, rsize_t | names from other headers | the 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
malloc | void *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 |
calloc | void *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 |
realloc | void *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_alloc | void *aligned_alloc(size_t alignment, size_t size) | reserves space at a given alignment | ★ size must be a multiple of alignment |
free | void free(void *ptr) | gives it back | ★ Passing null is safe. ★ Calling it twice is undefined behaviour |
free_sized, free_aligned_sized | void free_sized(void *ptr, size_t size), void free_aligned_sized(void *ptr, size_t alignment, size_t size) | gives it back, stating the size | C23. It frees the allocator from recording the size — ★ the wrong size is undefined behaviour |
memalignment | size_t memalignment(const void *p) | the alignment that address satisfies | C23 |
Table 105.51 — <stdlib.h> reference — memory allocation
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
exit | void exit(int status) | normal termination; does not return | runs what atexit registered and flushes the streams. ★ Must not be called from a signal handler |
quick_exit | void quick_exit(int status) | quick termination | runs only what at_quick_exit registered — it does not flush streams |
_Exit | void _Exit(int status) | immediate termination | ★ Runs nothing that was registered. The only termination safe in a signal handler |
abort | void abort(void) | abnormal termination | raises SIGABRT. ★ Flushing the streams is not guaranteed |
atexit, at_quick_exit | int 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 |
system | int 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 |
getenv | char *getenv(const char *name) | the value, or null | ★ The string must not be modified, and the next call may overwrite it |
getenv_s | the Annex K version | it also reports the length | ★K (chapter 83) |
EXIT_SUCCESS, EXIT_FAILURE | macros | values 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
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
atoi, atol, atof | int atoi(const char *nptr) and so on | the value read | ★★ They cannot report failure. “Zero” and “could not read it” are indistinguishable — not for new code |
strtol, strtoul | long strtol(const char * restrict nptr, char ** restrict endptr, int base) and so on | the 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, strtold | the floating versions | same | ★ The decimal point follows LC_NUMERIC — a common way to break a file format (chapter 73) |
strtod32, strtod64, strtod128 | the decimal floating versions | same | optional |
strfromd, strfromf, strfroml | int strfromd(char * restrict s, size_t n, const char * restrict format, double fp) and so on | the other direction — number to string. Like snprintf it returns the length it wanted | C23. ★ Unaffected by the locale, which makes it right for file formats |
strfromd32, strfromd64, strfromd128 | the decimal versions | same | optional |
Table 105.53 — <stdlib.h> reference — between strings and numbers
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
abs, labs, llabs | int abs(int j) and so on | absolute value | ★ The most negative value is not representable — undefined behaviour |
div, ldiv, lldiv | div_t div(int numer, int denom) and so on | quotient and remainder at once | div_t, ldiv_t and lldiv_t hold quot and rem |
qsort | void 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 |
bsearch | void *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_s | the Annex K versions | they take a context pointer | ★K better, since the comparison can carry state |
rand, srand | int 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, wctomb | int mblen(const char *s, size_t n) and so on | one 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, wcstombs | whole strings | characters converted | ★ Termination is not guaranteed — an exact fit leaves it off |
| Annex K conversions | mbstowcs_s, wcstombs_s, wctomb_s | the Annex K versions | ★K |
MB_CUR_MAX | macro | the most bytes per character in the current locale | ★ Not a constant — it changes with the locale |
RAND_MAX | macro | the upper bound of rand | at least 32767 |
Table 105.54 — <stdlib.h> reference — arithmetic, sorting, randomness, multibyte
| Name | What | Note |
|---|---|---|
set_constraint_handler_s | sets what runs when a contract is violated | ★K of type constraint_handler_t |
abort_handler_s, ignore_handler_s | a handler that ends at once; one that ignores | ★K the two provided |
call_once, ONCE_FLAG_INIT | re-exposed from <threads.h> | |
NULL, size_t, wchar_t, errno_t, rsize_t | names from other headers | the 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.
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
fopen | FILE *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 |
freopen | FILE *freopen(const char * restrict filename, const char * restrict mode, FILE * restrict stream) | reopens an existing stream on another file | used to point stdin or stdout at a file |
fclose | int 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 |
fflush | int fflush(FILE *stream) | flushes the buffer | ★ A null argument flushes every output stream. ★ Calling it on an input stream is undefined behaviour |
setbuf, setvbuf | void 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, rename | int 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, tmpnam | FILE *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
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
fgetc, getc, getchar | int fgetc(FILE *stream) and so on | one 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, putchar | int fputc(int c, FILE *stream) and so on | the character written, or EOF | ★ putc may be a macro too |
ungetc | int ungetc(int c, FILE *stream) | pushes one character back | ★ Only one is guaranteed |
fgets | char *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, puts | int fputs(const char * restrict s, FILE * restrict stream), int puts(const char *s) | writes | ★ puts appends a newline; fputs does not |
fread, fwrite | size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream) and so on | the 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 family | printf, fprintf, sprintf, snprintf | characters written | ★★ sprintf knows no length — use snprintf. ★ snprintf returns the length it wanted, which is how you detect truncation |
the vprintf family | vprintf, vfprintf, vsprintf, vsnprintf | the versions taking a va_list | (chapter 63) |
the scanf family | scanf, fscanf, sscanf | the 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 family | vscanf, vfscanf, vsscanf | the versions taking a va_list |
Table 105.57 — <stdio.h> reference — reading and writing
| Name | Form | Arguments and return | What it does · ★trap |
|---|---|---|---|
fseek, ftell | int fseek(FILE *stream, long offset, int whence), long ftell(FILE *stream) | moves and reports the position | whence 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, fsetpos | int 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 |
rewind | void rewind(FILE *stream) | returns to the start and clears the error indicator | ★ It returns nothing — failure cannot be detected |
feof, ferror, clearerr | int feof(FILE *stream) and so on | ask 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 |
perror | void perror(const char *s) | writes the message for errno to standard error | prefixed with s |
Table 105.58 — <stdio.h> reference — position and state
| Family | Names | Note |
|---|---|---|
| streams | stdin, stdout, stderr | ★ stderr is unbuffered or line-buffered |
| macros | EOF, 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 |
| types | FILE, fpos_t, size_t | ★ Do not look inside a FILE |
| Annex K | fopen_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.
| Rule | Meaning | Example |
|---|---|---|
suffix f, l | the float and long double versions | sqrtf, sqrtl |
<tgmath.h> | a macro that picks the suffix for you | one sqrt(x) for all three |
| decimal names | anything with d32, d64 or d128 is for decimal floating point | optional, and often absent |
Table 105.60 — How to read the names
| Name | What it asks | ★trap |
|---|---|---|
fpclassify | one of FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL | |
isnan, isinf, isfinite, isnormal | NaN, infinite, finite, normal | ★ Use isnan rather than x != x |
issubnormal, iszero, iscanonical, issignaling | subnormal, zero, canonical, signalling NaN | C23 |
signbit | whether the sign bit is set | ★ True for -0.0 — which x < 0 is not |
isgreater, isgreaterequal, isless, islessequal, islessgreater, isunordered | compare without raising an exception on NaN | ★ Plain > and < raise on a signalling NaN |
iseqsig | tests equality but raises on NaN | C23 |
totalorder, totalordermag | compare using the IEEE 754 total order | C23. It even separates -0.0 from +0.0 |
Table 105.61 — Asking what a value is — these are macros
| Family | Names | Note · ★trap |
|---|---|---|
| trigonometric | sin, cos, tan, asin, acos, atan, atan2 | ★ atan2 resolves the quadrant — the argument order is (y, x) |
| multiples of | sinpi, cospi, tanpi, asinpi, acospi, atanpi, atan2pi | C23. The argument is taken as a multiple of , which is more accurate |
| hyperbolic | sinh, cosh, tanh, asinh, acosh, atanh | |
| exponential | exp, exp2, exp10, expm1, exp2m1, exp10m1 | ★ expm1 computes accurately for small x |
| logarithmic | log, log2, log10, log1p, logp1, log2p1, log10p1, logb, ilogb, llogb | ★ log1p is the accurate form of |
| powers | pow, pown, powr, rootn, compoundn, sqrt, rsqrt, cbrt, hypot | ★ hypot finds the hypotenuse without overflowing in between |
| error and gamma | erf, erfc, lgamma, tgamma | ★ lgamma is the logarithm of the gamma function |
Table 105.62 — The elementary functions
| Family | Names | Note · ★trap |
|---|---|---|
| rounding | ceil, floor, trunc, round, roundeven, nearbyint, rint, lrint, llrint, lround, llround | ★ rint follows the current rounding direction and may raise; nearbyint does not |
| to an integer | fromfp, ufromfp, fromfpx, ufromfpx | C23. You choose the direction and the width |
| remainders | fmod, remainder, remquo | ★ fmod and remainder differ in sign |
| scaling | ldexp, scalbn, scalbln, frexp, modf | ★ frexp and modf return the other half through a pointer argument |
| maximum and minimum | fmax, 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 neighbours | fabs, copysign, nextafter, nexttoward, nextup, nextdown | ★ nextafter gives the very next representable value |
| making NaNs | nan, getpayload, setpayload, setpayloadsig, canonicalize | C23 opened a way to work with a NaN’s payload |
Table 105.63 — Rounding, remainders, moving the exponent
| Family | Names | Note |
|---|---|---|
| multiply and add | fma | ★ It rounds the multiplication and addition only once — the heart of precision |
float result | fadd, fsub, fmul, fdiv, fsqrt, ffma | C23. Computed in a wider type, rounded once to float |
double result | daddl, dsubl, dmull, ddivl, dsqrtl, dfmal | computed in long double, rounded to double |
| decimal versions | d32addd64, d32addd128, d64addd128, d32subd64, d32subd128, d64subd128, d32muld64, d32muld128, d64muld128, d32divd64, d32divd128, d64divd128, d32sqrtd64, d32sqrtd128, d64sqrtd128, d32fmad64, d32fmad128, d64fmad128 | the same for decimal floating point |
Table 105.64 — Keeping precision — computed wide, rounded once
| Family | Names | Note |
|---|---|---|
| quantum | quantized32, quantized64, quantized128, quantumd32, quantumd64, quantumd128, samequantumd32, samequantumd64, samequantumd128, llquantexpd32, llquantexpd64, llquantexpd128 | in decimal, the same value can be held at different quanta — these work with that |
| encoding | encodedecd32, encodedecd64, encodedecd128, decodedecd32, decodedecd64, decodedecd128, encodebind32, encodebind64, encodebind128, decodebind32, decodebind64, decodebind128 | move 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>.