Skip to content
Related Articles

Related Articles

Improve Article

X-Macros in C

  • Difficulty Level : Hard
  • Last Updated : 16 Apr, 2019

X-Macros are based on the property of nested macros and the ability to define macros inside other macros. X-Macros are very powerful pre-processor technique in the sense that it can create a self-maintaining and inter-dependent piece of code. When the change of one part of a program leads to a change in another part, then the code is said to be inter-dependent.

Syntax:
An X macro application consists of two parts:

  • The definition of the list’s elements:
    #define VARIABLES \
        X(value1, 1)  \
        .
        .
        .  \
        X(valueN, N)
    
  • Expansion(s) of the list to generate fragments of declarations or statements:
    #define X(name) int name;
        VARIABLES
    #undef X
    

The list is defined by a macro or header file (named, VARIABLES) which generates no code by itself, but merely consists of a sequence of invocations of a macro (classically named “X”) with the elements’ data. Each expansion of VARIABLES is preceded by a definition of X with the syntax for a list element. The invocation of VARIABLES expands X for each element in the list.

Implementations:

  • Example 1: Following Code explains the working of X-Macros:




    #include <stdio.h>
      
    // Defines four variables.
    #define VARIABLES \
        X(value1, 1)  \
        X(value2, 2)  \
        X(value3, 3)  \
        X(value4, 4)
      
    // driver program.
    int main(void)
    {
        // Declaration of every variable
        // is done through macro.
        #define X(value, a) char value[10];
            VARIABLES
        #undef X
          
        // String values are accepted
        // for all variables.
        #define X(value, a) scanf("\n%s", value);
            VARIABLES
        #undef X
          
        // Values are printed.
        #define X(value, a) printf("%d) %s\n", a, value);
            VARIABLES
        #undef X
        return 0;
    }
    Output:



    1) geeks
    2) for
    3) geeks
    4) geeksforgeeks
    

    In the above code addition of one or more variables in the Macro “VARIABLES” will lead to its automatic declaration, scanning as well as printing. This simple example clears the working and power of X-Macros. After expansion the above code will look like the code below:




    #include <stdio.h>
      
    int main(void)
    {
        char value1[10];
        char value2[10];
        char value3[10];
        char value4[10];
      
        scanf("\n%s", value1);
        scanf("\n%s", value2);
        scanf("\n%s", value3);
        scanf("\n%s", value4);
      
        printf("%d) %s\n", 1, value1);
        printf("%d) %s\n", 2, value2);
        printf("%d) %s\n", 3, value3);
        printf("%d) %s\n", 4, value4);
        return 0;
    }
    Output:
    1) geeks
    2) for
    3) geeks
    4) geeksforgeeks
    

    Although the above code simply explains the power of X-Macros, such use is rare and not recommended because it makes the code less readable. A more practical example is with enum or jump tables.

  • Example 2: Following code explains the working of X-Macros with enum:




    #include <stdio.h>
      
    // Defining a macro 
    // with the values of colors.
    #define COLORS \
        X(RED)     \
        X(BLACK)   \
        X(WHITE)   \
        X(BLUE)
      
    // Creating an enum of colors
    // by macro expansion.
    enum colors {
        #define X(value) value,
            COLORS
        #undef X
    };
      
    // A utility that takes the enum value
    // and returns corresponding string value
    char* toString(enum colors value)
    {
        switch (value) {
            #define X(color) \
                case color:  \
                    return #color;
                    COLORS
            #undef X
        }
    }
      
    // driver program.
    int main(void)
    {
        enum colors color = WHITE;
        printf("%s", toString(color));
        return 0;
    }
    Output:
    WHITE
    

    In the above code, any addition or removal of any constant from the COLORS macro will automatically reflect in the definition of enum as well as toString() function. Which is why X-Macros are used to produce self-maintaining codes. After macro expansion above code will look like the code below:




    #include <stdio.h>
      
    // Creating an enum of colors.
    enum colors {
        RED,
        BLACK,
        WHITE,
        BLUE
    };
      
    /*A utility that takes the enum value and returns 
    corresponding string value*/
    char* toString(enum colors value)
    {
        switch (value) {
        case RED:
            return "RED";
        case BLACK:
            return "BLACK";
        case WHITE:
            return "WHITE";
        case BLUE:
            return "BLUE";
        }
    }
      
    // driver program.
    int main(void)
    {
        enum colors color = WHITE;
        printf("%s", toString(color));
        return 0;
    }
    Output:
    WHITE
    

Advantages of X-Macros

  • X-Macros are extensively used in Operating System development by creating separate header files for maintainability as well as readability
  • Helps to maintain complex programming easily
  • it can create a self-maintaining and inter-dependent piece of code

Disadvantages of X-Macros

  • The code becomes less readable
  • Code is complex to understand
  • Commonly used for internal programming only, like OS programming.

Reference: https://en.wikipedia.org/wiki/X_Macro

Want to learn from the best curated videos and practice problems, check out the C Foundation Course for Basic to Advanced C.



My Personal Notes arrow_drop_up
Recommended Articles
Page :