--- title: cum.h related: - "[flag.h](flag.h.md)" - "[bt.h](bt.h.md)" categories: - C libraries --- **cum.h** is a set of Cursed yet Useful Macros for C and C++: recursive variadic macros, a type-agnostic dynamic array, a command runner, a stack, and small helpers. It is a single header, public domain. > [!NOTE] > It needs at least `-std=gnu99` or `-std=gnu++11`: it relies on GNU > extensions such as statement expressions, `__auto_type`, `__typeof__` and > `__VA_OPT__`. ## Recursive macros The C preprocessor does not allow recursion: while a macro is being expanded, its own name is "painted blue" and any appearance of it is left alone. cum.h works around this with the classic deferred-expansion trick: ``` #define _EMPTY() #define _DEFER(_id_) _id_ _EMPTY() #define OBSTRUCT(_id_) _id_ _DEFER(_EMPTY)() #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__))) #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__))) ... #define EVAL5(...) __VA_ARGS__ ``` - `OBSTRUCT(M)()` hides the call to `M` so it is not expanded during the current scan, only in a later one. At that point the macro is no longer "in use", so it can expand again. - `EVAL` forces the preprocessor to rescan its argument many times: every level triples the previous one, for 3⁵ = 243 scans. Each scan unrolls one step of the recursion. A recursive macro is then written as an `INNER` macro that handles the first argument and calls itself indirectly through an `INDIRECT` macro, while `__VA_OPT__` stops the recursion when there are no arguments left: ``` #define Join(_op_, ...) __VA_OPT__(EVAL(JOIN_INNER(_op_, __VA_ARGS__))) #define JOIN_INNER(_op_, a, ...) a __VA_OPT__(_op_ OBSTRUCT(JOIN_INDIRECT)()(_op_, __VA_ARGS__)) #define JOIN_INDIRECT() JOIN_INNER ``` ### Join `Join(op, a, b, c)` expands to `a op b op c`: ``` int sum = Join(+, x, y, z); // x + y + z if (Join(&&, ok1, ok2, ok3)) ... // ok1 && ok2 && ok3 ``` If the operator is a comma, use `__VA_ARGS__` directly. ### Unused `Unused(a, b, c)` expands to `(void) a; (void) b; (void) c;`, silencing unused-variable warnings for any number of names. ### Command_add Appends any number of arguments to a `Command`, one `Da_append` each: ``` Command cmd = { 0 }; Command_add(&cmd, "cc", "-o", "main", "main.c"); ``` ## Dynamic array `Da(type)` declares an anonymous struct with `capacity`, `count` and `items`: ``` Da(int) nums = { 0 }; Da_append(&nums, 42); Da_insert(&nums, 7, 0); Da_foreach(n, nums) printf("%d\n", *n); Da_destroy(&nums); ``` | Macro | Description | |---|---| | `Da_append(da, e)` | Add `e` at the end, doubling the capacity when full | | `Da_insert(da, e, i)` | Insert `e` at index `i` | | `Da_remove(da, i)`, `Da_remove_last(da)` | Remove an element | | `Da_index(elem_ptr, da)` | Index of an element given a pointer to it | | `Da_foreach(i, da)` | Iterate with `i` pointing to each element | | `Da_dup(da)` | Copy of the struct and its buffer | | `Da_destroy(da)` | Free the buffer and reset the array | `Ss(type)` is the same structure used as a stack, with `Ss_push`, `Ss_pop` and `Ss_top`. ## Commands `Command` is a `Da(char *)`. `DECLARE_COMMAND_RUN()` defines `Command_run(cmd)`, which forks, `execvp`s the command and waits for it. It returns the exit status, 127 if exec failed, or 1 if the fork failed or the child was killed by a signal. ``` DECLARE_COMMAND_RUN() Command cmd = { 0 }; Command_add(&cmd, "make", "-j8"); int status = Command_run(cmd); Command_destroy(&cmd); ``` ## Helpers | Macro | Description | |---|---| | `Let` | `__auto_type` in C, `auto` in C++ | | `Typeof(x)` | `__typeof__` / `typeof` | | `Todo(fmt, ...)` | Print file, line and message, then `abort()` | | `Min(a, b)`, `Max(a, b)` | Evaluate each argument once | | `Memdup(x)`, `Memzero(x)` | Heap copy / zero an object | | `KB(x)`, `MB(x)`, `GB(x)`, `TB(x)` | Sizes as `size_t` | | `Bf_set`, `Bf_clr`, `Bf_has` | Bit flags | | `Tostr(x)` | Stringify | ## Used by - [pm](pm.md). ## See also - [Source code](https://github.com/hugoocoto/cum.h) (public domain)