preprocessor-toolchain · beginner · ~15 min

Header Include Guard Simulation

Simulate the mechanics of preprocessor include guards and idempotent header compilation.

Challenge

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.

Your Task

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);

Rules

  1. If table == NULL, symbol == NULL, was_first_include == NULL, or cap == 0, return -1.
  2. Search table[0..cap-1] for an entry matching symbol with is_defined == 1.
  3. If found:
    • Set *was_first_include = 0.
    • Return 0 (header was guarded, body should NOT be re-included).
  4. If not found:
    • Find the first unused slot in table (where is_defined == 0).
    • If no unused slot exists, return -1 (table full).
    • Copy symbol into guard_symbol (NUL-terminated, truncating at 31 chars if longer).
    • Set is_defined = 1.
    • Set *was_first_include = 1.
    • Return 0 (first inclusion, body should be compiled).

Example

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

Input format

table: array of GuardTable; cap: size_t capacity; symbol: guard name string; was_first_include: output boolean indicator.

Output format

Returns 0 on successful processing, -1 on table full or NULL pointer.

Constraints

Zero dynamic allocations. Guard names up to 31 chars + NUL.

Starter code

#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;
}

Common mistakes

Overwriting existing entries instead of finding free slots; uninitialized memory comparisons.

Edge cases to handle

Including the same header 5 times only marks first=1 on the very first call; table full returns -1.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.