preprocessor-toolchain · advanced · ~15 min
Implement type-generic compile-time dispatch using C11 _Generic expressions.
C11 introduced _Generic expressions to provide compile-time type-based function dispatch without runtime overhead or void-pointer type erasure.
Implement type-specific serializers and a _Generic dispatcher macro:
int serialize_int(int val, char *buf, size_t cap);
int serialize_double(double val, char *buf, size_t cap);
int serialize_string(const char *val, char *buf, size_t cap);
#define SERIALIZE(x, buf, cap) ...
serialize_int: formats integer using snprintf(buf, cap, "%d", val). Returns written length or -1 on truncation/error.serialize_double: formats double using snprintf(buf, cap, "%.2f", val). Returns written length or -1 on truncation/error.serialize_string: copies string using snprintf(buf, cap, "%s", val ? val : "NULL"). Returns written length or -1 on truncation/error.SERIALIZE(x, buf, cap): uses _Generic on (x) to dispatch to serialize_int for int, serialize_double for double, serialize_string for char* and const char*.char out[32];
SERIALIZE(42, out, sizeof(out)); // out == "42"
SERIALIZE(3.1415, out, sizeof(out)); // out == "3.14"
SERIALIZE("test", out, sizeof(out)); // out == "test"
x: int, double, or string literal; buf: output buffer; cap: capacity.
Returns characters written or -1 on truncation.
Must use C11 _Generic selection macro.
#include <stddef.h>
#include <stdio.h>
int serialize_int(int val, char *buf, size_t cap) {
(void)val; (void)buf; (void)cap; return -1;
}
int serialize_double(double val, char *buf, size_t cap) {
(void)val; (void)buf; (void)cap; return -1;
}
int serialize_string(const char *val, char *buf, size_t cap) {
(void)val; (void)buf; (void)cap; return -1;
}
#define SERIALIZE(x, buf, cap) 0
Forgetting const char* branch in _Generic; missing parentheses around macro parameters.
Truncation returns -1; cap == 0 returns -1; NULL string formats as NULL.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.