How do I show the value of a #define at compile-time?

Jim Hunziker picture Jim Hunziker · Oct 13, 2009 · Viewed 115.9k times · Source

I am trying to figure out what version of Boost my code thinks it's using. I want to do something like this:

#error BOOST_VERSION

but the preprocessor does not expand BOOST_VERSION.

I know I could print it out at run-time from the program, and I know I could look at the output of the preprocessor to find the answer. I feel like having a way of doing this during compilation could be useful.

Answer

Chris Barry picture Chris Barry · May 29, 2012

I know that this is a long time after the original query, but this may still be useful.

This can be done in GCC using the stringify operator "#", but it requires two stages.

#define XSTR(x) STR(x)
#define STR(x) #x

The value of a macro can then be displayed with:

#pragma message "The value of ABC: " XSTR(ABC)

See: 3.4 Stringification in the gcc online documentation.

How it works:

The preprocessor understands quoted strings and handles them differently from normal text. String concatenation is an example of this special treatment. The message pragma requires an argument that is a quoted string. When there is more than one component to the argument then they must all be strings so that string concatenation can be applied. The preprocessor can never assume that an unquoted string should be treated as if it were quoted. If it did then:

#define ABC 123
int n = ABC;

would not compile.

Now consider:

#define ABC abc
#pragma message "The value of ABC is: " ABC

which is equivalent to

#pragma message "The value of ABC is: " abc

This causes a preprocessor warning because abc (unquoted) cannot be concatenated with the preceding string.

Now consider the preprocessor stringize (Which was once called stringification, the links in the documentation have been changed to reflect the revised terminology. (Both terms, incidentally, are equally detestable. The correct term is, of course, stringifaction. Be ready to update your links.)) operator. This acts only on the arguments of a macro and replaces the unexpanded argument with the argument enclosed in double quotes. Thus:

#define STR(x) #x
char *s1 = "abc";
char *s2 = STR(abc);

will assign identical values to s1 and s2. If you run gcc -E you can see this in the output. Perhaps STR would be better named something like ENQUOTE.

This solves the problem of putting quotes around an unquoted item, the problem now is that, if the argument is a macro, the macro will not be expanded. This is why the second macro is needed. XSTR expands its argument, then calls STR to put the expanded value into quotes.