Site Tools


c-x-macros

Table of Contents

C X macros

C X macros are a metaprogramming technique where a macro is defined to represent a list, then included multiple times with different expansions to generate repetitive code. The same list definition generates enums, string arrays, case statements, and parser tables without manual duplication.

Use X macros to keep related data (enums, strings, handlers) synchronized and avoid repetition when the same list is used in multiple contexts.

Example

This example shows X macros generating enums, strings, and case statements from one list.

// compile: gcc -o xmacros xmacros.c
// run: ./xmacros
// description: X macro pattern for code generation
 
#include <stdio.h>
#include <string.h>
 
// Define the list once (the "X" macro pattern)
#define COLORS_LIST \
    X(RED,     "Red",     0xFF0000) \
    X(GREEN,   "Green",   0x00FF00) \
    X(BLUE,    "Blue",    0x0000FF) \
    X(YELLOW,  "Yellow",  0xFFFF00) \
    X(CYAN,    "Cyan",    0x00FFFF)
 
// Generate enum
#define X(name, str, hex) name,
enum Color {
    COLORS_LIST
    COLOR_COUNT
};
#undef X
 
// Generate string array
#define X(name, str, hex) str,
const char *color_names[] = {
    COLORS_LIST
};
#undef X
 
// Generate RGB array
#define X(name, str, hex) hex,
const int color_values[] = {
    COLORS_LIST
};
#undef X
 
// Function to get color name
const char *color_name(enum Color c) {
    if (c >= 0 && c < COLOR_COUNT) {
        return color_names[c];
    }
    return "Unknown";
}
 
// Function to get color value
int color_value(enum Color c) {
    if (c >= 0 && c < COLOR_COUNT) {
        return color_values[c];
    }
    return 0;
}
 
int main() {
    printf("Color enumeration:\n");
    for (int i = 0; i < COLOR_COUNT; i++) {
        printf("  %d: %s (0x%06X)\n", i, color_name(i), color_value(i));
    }
 
    // Use enum and look up values
    enum Color c = BLUE;
    printf("\nSelected color: %s = 0x%06X\n", color_name(c), color_value(c));
 
    // Parse color by name
    const char *target = "GREEN";
    for (int i = 0; i < COLOR_COUNT; i++) {
        if (strcmp(color_names[i], target) == 0) {
            printf("Found %s at index %d (0x%06X)\n", target, i, color_value(i));
            break;
        }
    }
 
    return 0;
}

Common patterns

Single definition, multiple expansions:

  • Define macro NAME_LIST once with X(...) for each entry
  • Include multiple times with different #define X(...)
  • Each inclusion expands to different output (enum, strings, handlers)

Synchronization benefit:

  • Add/remove entry in one place
  • All generated code updates automatically
  • No manual enum/string/handler updates
  • Eliminates sync bugs

Common use cases:

  • Enums + string representations
  • Enums + handler functions
  • Enums + default values
  • Enums + printf formatters
  • Command handlers + dispatch tables
  • Error codes + error messages

Dispatch table example:

#define HANDLERS_LIST \
    X(CMD_START, handle_start) \
    X(CMD_STOP, handle_stop) \
    X(CMD_STATUS, handle_status)
 
// Generate enum
#define X(cmd, func) cmd,
enum Command { HANDLERS_LIST };
#undef X
 
// Generate handler table
#define X(cmd, func) func,
handler_t handlers[] = { HANDLERS_LIST };
#undef X

Variadic X usage:

  • X(name, ...) accepts multiple fields
  • Each expansion can use different subset
  • Flexible for complex data

Debugging gotcha:

  • Error messages show expanded code, not macro
  • Use gcc -E to see expansion
  • Add comments in list for clarity

Alternatives:

  • Python script to generate C code (external tool)
  • Code generator (build step)
  • Manual lists (prone to sync errors)
  • X macros (pure C, no build tools)

Limitations:

  • Macro syntax is cryptic
  • Hard to debug (preprocessor output)
  • Not type-safe (preprocessor is text-based)
  • Can't use in many contexts where C++ templates work

Style considerations:

  • #undef X after each use to avoid pollution
  • Long list definitions can be hard to read
  • Clear naming (COLORS_LIST, not LIST) helps
  • Document the X macro pattern in comments

Modern alternatives:

  • C++ templates (type-safe, readable)
  • Code generation tools (clearer separation)
  • Build scripts (flexible, external)
  • But X macros remain pure-C solution
c-x-macros.md · Last modified: by 127.0.0.1