Walter Bright

Dr. Dobb's Bloggers

The X Macro

June 24, 2010

I learned this technique over 30 years ago from friends of mine in college. It was for assembler language macros, but survived the transition to C macros easily. I've used it regularly since, but interestingly have never seen anyone else use it. That makes it my turn to pass along this little gem.

I learned this technique over 30 years ago from friends of mine in college. It was for assembler language macros, but survived the transition to C macros easily. I've used it regularly since, but interestingly have never seen anyone else use it. That makes it my turn to pass along this little gem.

To use a hackneyed example, let's have a header file color.h, and in that there's an enum for the colors:

enum Color { Cred, Cblue, Cgreen };

In the corresponding source file color.c, in order to pretty print colors, there's a corresponding array of strings:

static char *ColorStrings[] =
{"red", "blue", "green"};

which we can use like:

enum Color c;
...
printf("the color is %s\n",
ColorStrings[c]);

So far, so good. Time goes on, and another color is added:

enum Color
{ Cred, Cyellow, Cblue, Cgreen };

and yes, we forget to update the ColorStrings[] array, and not only does printing out Cyellow come out as "blue", even worse we have an array overflow printing out the string for Cgreen. (You're a smart programmer and would never make such a mistake, right?)

The trouble is there's no semantic connection between the enum and the array. The usual way to deal with this is to add a pack of unit tests. But wouldn't it be better if we could find a way to connect the dots at compile time? Is this a job for -- The X Macro -- ?

In other words, we redefine the X macro as necessary to extract the bit of information needed at the moment and ignore the rest. Proper macro hygiene is maintained because the #define of X will complain if X is already defined, and the #undef will ensure it doesn't muck up any later X.

and 3 separate but parallel constructions are built - the enum, the string table for pretty printing, and the characteristics array (from the second argument). The most complex example I use it for has 6 arguments to the X Macro, which builds enums, struct initializers, and runtime initializers.

Of course, you may already be using a macro or variable named X, and X is hardcoded in the macro body. Andrei Alexandrescu suggests the following improvement where the X macro is itself a parameter:

The X Macro technique works with any language with a half-decent text macro preprocessor, and C's is certainly up to the task. Use it and pass it along, as my friends were kind enough to pass it along to me.

(Like I said, I've never seen this used by others in the last 30 years. Is it really so obscure? Do you already use it? Post a comment!)

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!