Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I force an undefined macro to expand before stringification?

Tags:

c++

c

macros

Disclaimer: I have already looked at the answers to questions similar to Stringification of a macro value.

Consider the following test program:

#include <stdio.h>
#define QUOTE(str) #str
#define EXPAND_AND_QUOTE(str) QUOTE(str)

#define MACRO HelloWorld

int main() {
    printf("%s\n", EXPAND_AND_QUOTE(MACRO));
    printf("%s\n", QUOTE(MACRO));

    #undef MACRO
    printf("%s\n", EXPAND_AND_QUOTE(MACRO));
    printf("%s\n", QUOTE(MACRO));
}

The output of this program is:

HelloWorld
MACRO
MACRO
MACRO

The desired output is

HelloWorld
MACRO

MACRO

Is there a way to redefine my macros (that is, the meta-macros which are not MACRO) to get the desired output?

In particular, I want it to be the case that the third printf should be equivalent to:

printf("%s\n", QUOTE());

That is, I want the expansion of the undefined macro into "nothingness" and then have that "nothingness" passed to the quote function.

like image 252
merlin2011 Avatar asked Oct 18 '25 00:10

merlin2011


2 Answers

This is not possible in standard C.

There are four things that can happen to a token during macro replacement. It can remain unchanged, it can be substituted with a replacement value, it can be concatenated with another token, and it can be stringized.

If MACRO is unchanged, there is no way to distinguish these two situations:

#undef MACRO
printf("%s\n", EXPAND_AND_QUOTE(MACRO));

#define FOO MACRO
printf("%s\n", EXPAND_AND_QUOTE(FOO));

Once FOO is replaced in the latter, we have two situations: In one, we have MACRO because it is unchanged. In the other, we have MACRO because it was substituted for FOO. After that point, the behavior must be identical. But the problem requirements call for different behavior, "" for the former and "MACRO" for the latter. Since identical behavior cannot produce different results, this will not work. (But more about this below.)

The second possibility, substitution with another value, does not happen, since MACRO is not defined.

The third possibility merely produces some new token, such as FOOMACRO. However, although we can choose the first part, we cannot choose the latter part, so we cannot know what token will result, and there is nothing we might do with it that would differ depending on whether MACRO is defined or not.

The fourth possibility has the same problem as the third, we produce "MACRO" and can make no use of it.

The only vague hope I had of doing something with this is producing two tokens, one the result of letting the token be replaced and one not. E.g., we can produce a situation in which, given the above non-definition of MACRO and the definition of FOO, EXPAND_AND_QUOTE(MACRO) produces, somewhere in a chain of expansions of helper macros, two tokens SomethingMACRO and SomethingMACRO, while EXPAND_AND_QUOTE(FOO) produces SomethingFOO and SomethingMACRO. That is possible, but then what do we do with the two tokens? We could stringize both and then compare them with strcmp at run time. However, I do not think anything can be done at compile time. Also, it would fail to distinguish the situation in which FOO is defined as #define FOO FOO; that would, if we were successful in comparing the tokens described above, produce "", but the requirements call for it to produce "FOO".

like image 76
Eric Postpischil Avatar answered Oct 20 '25 15:10

Eric Postpischil


Try this:

#undef MACRO
#define MACRO

Alternatively:

#undef MACRO
#ifndef MACRO
#  undef EXPAND_AND_QUOTE
#  define EXPAND_AND_QUOTE(str) ""
#endif
like image 21
Kerrek SB Avatar answered Oct 20 '25 15:10

Kerrek SB



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!