X-Macros in C

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:
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

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

    chevron_right

    
    

    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:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

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

    chevron_right

    
    

    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:
    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

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

    chevron_right

    
    

    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:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

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

    chevron_right

    
    

    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



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.




Article Tags :
Practice Tags :


Be the First to upvote.


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.