Macro Utilities¶
A comprehensive suite of small, dependency-free macros for everyday C work: numeric comparison and clamping, interpolation and shading curves, angle conversion, array and struct introspection, generic swapping, bitwise and power-of-two alignment helpers, and AI activation functions. Every macro wraps its arguments in parentheses to avoid operator-precedence bugs, and the short-name aliases are guard-checked so they never collide with code you already have.
Arithmetic and comparison¶
| Macro | Result |
|---|---|
ABS_MIN(a, b) / ABS_MAX(a, b) |
the smaller / larger of a and b |
ABS_MIN3(a, b, c) / ABS_MAX3(a, b, c) |
min / max of three arguments |
ABS_MIN4(a, b, c, d) / ABS_MAX4(a, b, c, d) |
min / max of four arguments |
ABS_ABS(x) |
absolute value |
ABS_SIGN(x) |
1 if positive, -1 if negative, 0 if zero |
ABS_CLAMP(x, lo, hi) |
x clamped into [lo, hi] |
ABS_CLAMP01(x) |
x clamped into [0, 1] |
ABS_IN_RANGE(x, min, max) |
non-zero if min <= x <= max |
double v = 14.8;
v = ABS_CLAMP(v, 0.0, 12.0); /* 12.0 */
int flag = ABS_SIGN(-4); /* -1 */
int hot = ABS_IN_RANGE(37.2, 36.5, 37.5); /* 1 */
Powers, differences, and approximate equality¶
| Macro | Result |
|---|---|
ABS_SQR(x) |
x * x |
ABS_CUBE(x) |
x * x * x |
ABS_DIFF(a, b) |
absolute difference abs(a - b) |
ABS_APPROX_EQ(a, b, eps) |
non-zero when |a - b| <= eps |
Interpolation and shading curves¶
| Macro | Result |
|---|---|
ABS_LERP(a, b, t) |
a + t * (b - a) — linear interpolation between a and b |
ABS_UNLERP(a, b, val) |
inverse of LERP: the t that maps a→0 and b→1 |
ABS_REMAP(val, in_a, in_b, out_a, out_b) |
re-scale val from one range to another |
ABS_STEP(edge, x) |
0.0 if x < edge, otherwise 1.0 |
ABS_SMOOTHSTEP(e0, e1, x) |
Hermite-smoothed 3t² - 2t³ step in [0, 1] |
ABS_SMOOTHSTEP is backed by a portable static inline function (evaluating its arguments exactly once), so it works on GCC, Clang, and MSVC alike.
double t = ABS_LERP(0.0, 1.0, 0.5); /* 0.5 */
double c = ABS_REMAP(2.5, 0.0, 5.0, -40.0, 125.0); /* 42.5 */
double s = ABS_SMOOTHSTEP(0.0, 1.0, 0.75); /* 0.84375 */
Angle conversion¶
| Macro | Result |
|---|---|
ABS_DEG2RAD_M(deg) |
degrees → radians (deg * ABS_PI / 180) |
ABS_RAD2DEG_M(rad) |
radians → degrees (rad * 180 / ABS_PI) |
Array, struct, and memory utilities¶
| Macro | Result |
|---|---|
ABS_ARRAY_LEN(arr) |
number of elements in a stack array (sizeof(arr) / sizeof(arr[0])) |
ABS_OFFSETOF(type, member) |
byte offset of member within type (standard offsetof from <stddef.h>) |
ABS_CONTAINER_OF(ptr, type, member) |
recover the enclosing struct pointer from a member pointer |
typedef struct { u32 id; f32 health; vec3 position; } Entity;
Entity e = {101, 100.0f, v3(1.0f, 2.0f, 3.0f)};
size_t off = ABS_OFFSETOF(Entity, position); /* 8 */
Entity *back = ABS_CONTAINER_OF(&e.position, Entity, position); /* &e */
Generic swap¶
ABS_SWAP(a, b) swaps two values of any (identical) type — integers, floats, structs — via a __typeof__ temporary on GCC/Clang. On compilers without __typeof__, use ABS_SWAP_T(type, a, b) which takes the type explicitly.
Bitwise and alignment helpers¶
| Macro | Result |
|---|---|
ABS_BIT(n) |
1ULL << n |
ABS_BIT_SET(x, n) |
set bit n of x (in place) |
ABS_BIT_CLEAR(x, n) |
clear bit n of x (in place) |
ABS_BIT_TOGGLE(x, n) |
flip bit n of x (in place) |
ABS_BIT_CHECK(x, n) |
non-zero if bit n of x is set |
ABS_IS_POW2(x) |
non-zero if x is a power of two |
ABS_ALIGN_UP(x, align) |
round x up to a multiple of align |
ABS_ALIGN_DOWN(x, align) |
round x down to a multiple of align |
align must be a power of two (as is usual for alignment math).
u32 flags = 0;
ABS_BIT_SET(flags, 3);
ABS_BIT_SET(flags, 5); /* flags == 40 */
ABS_BIT_CHECK(flags, 3); /* 1 */
ABS_BIT_CLEAR(flags, 3); /* flags == 32 */
size_t up = ABS_ALIGN_UP(1040, 512); /* 1536 */
int ok = ABS_IS_POW2(512); /* 1 */
AI activation helpers¶
| Macro | Result |
|---|---|
ABS_RELU_M(x) |
max(0, x) |
ABS_LEAKY_RELU_M(x, alpha) |
x if positive, else alpha * x |
ABS_HEAVISIDE_M(x) |
1.0 if x >= 0, else 0.0 |
double a = ABS_LEAKY_RELU_M(-4.5, 0.01); /* -0.045 */
double b = ABS_RELU_M(-4.5); /* 0.0 */
double c = ABS_HEAVISIDE_M(-4.5); /* 0.0 */
Short-name aliases¶
The most common macros also ship as guard-checked unprefixed aliases — each is defined only if a macro of that name does not already exist, so they cannot collide with your own code:
MIN · MAX · CLAMP · CLAMP01 · LERP · REMAP · SIGN · SQR · ARRAY_LEN · SWAP · DEG2RAD · RAD2DEG · BIT · IS_POW2
MIN(12.5, 48.2) /* 12.5 */
CLAMP(14.8, 0.0, 12.0) /* 12.0 */
LERP(100, 200, 0.5) /* 150.0 */
ARRAY_LEN(samples) /* element count */
DEG2RAD(90.0) /* PI / 2 */
Prefer the ABS_-prefixed forms in library code and reserve the short names for application code where brevity matters.
Related: Common Macros for ABS_API and header plumbing, General Mathematics for the function-based scalar utilities, and Spatial Math for vectors, matrices, and quaternions.
Back to README.