Is it necessary to check definition of a macro in the C preprocessor?

Viewed 73

I am reading some C code and found preprocessors like this appear pretty frequently:

#if defined(ZERO_MIN_SUPPORT) && (ZERO_MIN_SUPPORT==1)
        minimum = 0x0,
#else
        minimum = 0x1,
#endif

I am wondering that, compared to #if ZERO_MIN_SUPPORT, does it have any advantages, or just a coding style?

In my view, no matter whether ZERO_MIN_SUPPORT is 1, 0, or undefined, #if ZERO_MIN_SUPPORT is always equivalent to #if defined(ZERO_MIN_SUPPORT) && (ZERO_MIN_SUPPORT==1).

4 Answers

In my view, no matter whether ZERO_MIN_SUPPORT is 1, 0, or undefined, #if ZERO_MIN_SUPPORT is always equivalent to #if defined(ZERO_MIN_SUPPORT) && (ZERO_MIN_SUPPORT==1)

So test it!

#define ZERO_MIN_SUPPORT 2
#if ZERO_MIN_SUPPORT
#error apparently I am mistaken
#endif

The original matches only if ZERO_MIN_SUPPORT is defined as 1. Your version allows it to be any value other than zero.

That specific code could be rewritten as #if ZERO_MIN_SUPPORT==1. It can not be rewritten as #if ZERO_MIN_SUPPORT like you claim, since that would return 1 no matter the value, as long as ZERO_MIN_SUPPORT is defined (and not zero).

In general, programmers tend to avoid #if checks infavour of ifdef/#if defined since the former silently evaluates to 0 in case the operator isn't defined. For example:

#if APPLES == ORANGES
  #error Apples are oranges
#endif

This makes an incorrect conclusion if neither identifier is defined.

From the C programming language standard, 6.10.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.

and 6.10.4:

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.

Your question:

In my view, no matter whether ZERO_MIN_SUPPORT is 1, 0, or undefined, #if ZERO_MIN_SUPPORT is always equivalent to #if defined(ZERO_MIN_SUPPORT) && (ZERO_MIN_SUPPORT==1).

These are not equivalent, as #if ZERO_MIN_SUPPORT tests for any non-zero value, whereas #if defined(ZERO_MIN_SUPPORT) && (ZERO_MIN_SUPPORT==1) specifically tests for 1.
It is the case that the latter could be shortened to #if (ZERO_MIN_SUPPORT==1).

In my view, no matter whether ZERO_MIN_SUPPORT is 1, 0, or undefined, #if ZERO_MIN_SUPPORT is always equivalent to #if defined(ZERO_MIN_SUPPORT) && (ZERO_MIN_SUPPORT==1).

This is a fact, not merely a view, as we can demonstrate by evaluating all the possibilities:

ZERO_MIN_SUPPORT #if ZERO_MIN_SUPPORT #if defined(ZERO_MIN_SUPPORT) && (ZERO_MIN_SUPPORT==1)
1 true true
0 false false
undefined false false

However, outside the options you list, they differ:

ZERO_MIN_SUPPORT #if ZERO_MIN_SUPPORT #if defined(ZERO_MIN_SUPPORT) && (ZERO_MIN_SUPPORT==1)
2 true false

I am wondering that, compared to #if ZERO_MIN_SUPPORT, does it have any advantages, or just a coding style?

In the absence of any studies of the rate at which humans make mistakes with one or the other, whether one has advantages over the other is largely a matter of opinion and conjecture. Generally, shorter or simpler code is favored if it is not unnecessarily obtuse. Unless there is some reason to treat definitions other than undefined, 0, and 1 as false, the former performs the desired function and is simpler and shorter.

If there is some reason to treat other definitions as false, then #if ZERO_MIN_SUPPORT == 1 performs that and is simpler and shorter than the original code.

Related