# 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. ```c // compile: gcc -o xmacros xmacros.c // run: ./xmacros // description: X macro pattern for code generation #include #include // 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**: ```c #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