What value to expect from a macro that has been set to the result of defined()?

242 views Asked by At

In the very simple C program below, what is the expected compiler error? gcc is giving me 1 whereas MSVC 2013 is giving me 2.

#define foo
#define bar (defined(foo))

#if bar
#error 1
#else
#error 2
#endif

My questions are hopefully equally simple:

  1. What does the C spec say about the value of defined()? I can't seem to find anything that talks about setting its value to another macro.
  2. The actual code is not something I have control over and "#if bar" is used all over the place. What is the simplest way to change the #define so that #if bar will work as "expected" in MSVC? The only thing I can think of is to expand it out:

.

#ifdef foo
#define bar 1
#else
#define bar 2
#endif
2

There are 2 answers

3
Mooing Duck On BEST ANSWER

The C spec says:

§6.10.1/1 The expression ... may contain unary operator expressions of the form defined identifier or defined(identifier) which evaluate to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has been the subject of a #define preprocessing directive without an intervening #undef directive with the same subject identifier), 0 if it is not.

§6.10.1/4 macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary operator), just as in normal text. If the token defined is generated as a result of this replacement process or use of the defined unary operator does not match one of the two specified forms prior to macro replacement, the behavior is undefined. After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number 0, and then each preprocessing token is converted into a token.

(emphasis mine) However, how macro replacement is very complex, and I think MSVC is defining foo as defined(bar) which is undefined behavior, wheras GCC is defining foo as 1 correctly. Since MSVC is then in undefined behavior, it does strange things.

As you say, the easiest fix is

#ifdef foo
#define bar 1
#else
#define bar 2
#endif
4
Paul Ogilvie On

I believe the compiler will see everything after the name/macro being defined as part of the definition of the name/macro, that is, as program text, not as macro text.

int defined(char s);    // prototype of a function named "defined"

#define foo
#define bar defined(foo)

"bar" anywhere in the program text will now be replaced with a call to defined() with no argument (as "foo" is defined as empty).