X-Macros in C
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>
#define VARIABLES \
X(value1, 1) \
X(value2, 2) \
X(value3, 3) \
X(value4, 4)
int main( void )
{
#define X(value, a) char value[10];
VARIABLES
#undef X
#define X(value, a) scanf("\n%s", value);
VARIABLES
#undef X
#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>
#define COLORS \
X(RED) \
X(BLACK) \
X(WHITE) \
X(BLUE)
enum colors {
#define X(value) value,
COLORS
#undef X
};
char * toString( enum colors value)
{
switch (value) {
#define X(color) \
case color: \
return #color;
COLORS
#undef X
}
}
int main( void )
{
enum colors color = WHITE;
printf ( "%s" , toString(color));
return 0;
}
|
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>
enum colors {
RED,
BLACK,
WHITE,
BLUE
};
char * toString( enum colors value)
{
switch (value) {
case RED:
return "RED" ;
case BLACK:
return "BLACK" ;
case WHITE:
return "WHITE" ;
case BLUE:
return "BLUE" ;
}
}
int main( void )
{
enum colors color = WHITE;
printf ( "%s" , toString(color));
return 0;
}
|
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
Share your thoughts in the comments
Please Login to comment...