preprocessor-toolchain · beginner · ~15 min
Simulate the mechanics of preprocessor include guards and idempotent header compilation.
Header include guards (#ifndef HEADER_H, #define HEADER_H, #endif) prevent duplicate type definitions and token collisions when a header file is included multiple times across a translation unit.
Implement an include guard state table:
typedef struct {
char guard_symbol[32];
int is_defined;
} GuardTable;
int guard_process_include(GuardTable *table, size_t cap, const char *symbol, int *was_first_include);
table == NULL, symbol == NULL, was_first_include == NULL, or cap == 0, return -1.table[0..cap-1] for an entry matching symbol with is_defined == 1.*was_first_include = 0.0 (header was guarded, body should NOT be re-included).table (where is_defined == 0).-1 (table full).symbol into guard_symbol (NUL-terminated, truncating at 31 chars if longer).is_defined = 1.*was_first_include = 1.0 (first inclusion, body should be compiled).GuardTable guards[4] = {0};
int first = 0;
guard_process_include(guards, 4, "CONFIG_H", &first); // returns 0, first == 1
guard_process_include(guards, 4, "CONFIG_H", &first); // returns 0, first == 0
table: array of GuardTable; cap: size_t capacity; symbol: guard name string; was_first_include: output boolean indicator.
Returns 0 on successful processing, -1 on table full or NULL pointer.
Zero dynamic allocations. Guard names up to 31 chars + NUL.
#include <stddef.h>
#include <string.h>
typedef struct {
char guard_symbol[32];
int is_defined;
} GuardTable;
int guard_process_include(GuardTable *table, size_t cap, const char *symbol, int *was_first_include) {
(void)table; (void)cap; (void)symbol; (void)was_first_include;
return -1;
}
Overwriting existing entries instead of finding free slots; uninitialized memory comparisons.
Including the same header 5 times only marks first=1 on the very first call; table full returns -1.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.