The subtle difference between #ifdef and #if for a

2019-04-28 09:18发布

Given the C file below:

$ cat macros.c
#ifdef MACRO
#  error MACRO is defined
#else
#  error MACRO is undefined
#endif
#if MACRO
#  error MACRO is non-zero
#else
#  error MACRO is zero
#endif

What is the expected output of the following?

$ gcc           -c macros.c
$ gcc -DMACRO   -c macros.c
$ gcc -DMACRO=0 -c macros.c

Answer: Here's what the gcc's preprocessor on my machine does.

$ gcc           -c macros.c
macros.c:4:4: error: #error MACRO is undefined
macros.c:9:4: error: #error MACRO is zero
$ gcc -DMACRO   -c macros.c
macros.c:2:4: error: #error MACRO is defined
macros.c:7:4: error: #error MACRO is non-zero
$ gcc -DMACRO=0 -c macros.c
macros.c:2:4: error: #error MACRO is defined
macros.c:9:4: error: #error MACRO is zero
$

Lesson: #ifdef MACRO evaluates to true for defined-ness even if the defined value is 0 (zero).

Another C preprocessor gotcha! Is this how it should be as per the C standard?

3条回答
做个烂人
2楼-- · 2019-04-28 09:51

Any undefined macro is treated as it were defined as 0 for the purposes of evaluating the controlling expressions of #if statements. From C99 §6.10.1/3-4 (emphasis added):

3) Preprocessing directives of the forms

# if constant-expression new-line groupopt
# elif constant-expression new-line groupopt

check whether the controlling constant expression evaluates to nonzero.

4) Prior to evaluation, 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. [...]

So, for example, expressions like this:

#if !FOO

Will evaluate to 1 if FOO is undefined, since it will be treated as a 0, and then !FOO would be evaluated as !0, which is 1.

查看更多
小情绪 Triste *
3楼-- · 2019-04-28 10:02

#ifdef only cares if MACRO has been defined or not. Value doesn't matter.

#if checks for the value of MACRO and evaluates MACRO accordingly.

That is correct behaviour

查看更多
\"骚年 ilove
4楼-- · 2019-04-28 10:02

The behavior is as per the standard.

C99 Standard: 6.10.1 Conditional inclusion:

Para 2: Preprocessing directives of the forms

# if constant-expression new-line groupopt
# elif constant-expression new-line groupopt

check whether the controlling constant expression evaluates to nonzero.

Para 4: Preprocessing directives of the forms

# ifdef identifier new-line groupopt
# ifndef identifier new-line groupopt

check whether the identifier is or is not currently defined as a macro name. Their conditions are equivalent to #if defined identifier and #if !defined identifier respectively.

查看更多
登录 后发表回答