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:

Synchronization benefit:

Common use cases:

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:

Debugging gotcha:

Alternatives:

Limitations:

Style considerations:

Modern alternatives: