Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The subtle difference between #ifdef and #if for a macro defined as 0

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?

like image 847
vapace Avatar asked Jan 23 '14 15:01

vapace


2 Answers

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.

like image 57
Adam Rosenfield Avatar answered Oct 02 '22 15:10

Adam Rosenfield


#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

like image 34
diddles Avatar answered Oct 02 '22 15:10

diddles