Is #if defined MACRO equivalent to #ifdef MACRO?

2020-02-03 16:43发布

问题:

I have code that I want to have two modes, debug and verbose. I define them in my header file as,

#define verbose TRUE
#define debug TRUE

In my code so far, I have just been using

#if(debug)
  //code
#endif

but is it more proper to use

#ifdef debug
  // code
#endif

I read something about preprocessor macros but it didn't make sense at the time. So, I have question, Is #if defined MACRO equivalent to #ifdef MACRO? and which is better to enabling/disabling particular section of code?

回答1:

#ifdef MACRO
#if defined (MACRO)

will do the exact same thing. However, the defined (MACRO) is just an expression that evaluates to 0 or 1 inside the #if, and it can be combined with other expressions. For example

#if defined (MACRO) && ! defined (MACRO2)
    // Do this
#else
    // Do that
#endif

Try doing that with #ifdef - you can't unless your code gets really clumsy.



回答2:

#if defined(MACRO) is the same as #ifdef MACRO, but is longer. On the other hand it allows to add extra conditions with || or &&.

#if MACRO is similar to #ifdef MACRO but not 100%. If MACRO is 0 then #if MACRO will be negative - it requires MACRO to be defined and not be 0. #ifdef checks only whether it is defined even without value (#define MACRO).

Now is modern to use #if and enable/disable definitions with value 1 or 0:

#define FLAG_X 1 // or 0



回答3:

No, they are not at all equivalent. An #if MACRO branch is compiled if MACRO evaluates to non-zero. On the other hand, an #ifdef MACRO branch is compiled if MACRO is defined, no matter what it evaluates to. So

#include <stdio.h>

#define VAR_SET_TO_TRUE 1
#define VAR_SET_TO_FALSE 0

int main()
{

#if VAR_SET_TO_TRUE
    printf("#if VAR_SET_TO_TRUE\n");
#endif

#if VAR_SET_TO_FALSE
    printf("#if VAR_SET_TO_FALSE\n");
#endif

#if VAR_UNSET
    printf("#if VAR_UNSET\n");
#endif



#ifdef VAR_SET_TO_TRUE
    printf("#ifdef VAR_SET_TO_TRUE\n");
#endif

#ifdef VAR_SET_TO_FALSE
    printf("#ifdef VAR_SET_TO_FALSE\n");
#endif

#ifdef VAR_UNSET
    printf("#ifdef VAR_UNSET\n");
#endif

}

will output

#if VAR_SET_TO_TRUE
#ifdef VAR_SET_TO_TRUE
#ifdef VAR_SET_TO_FALSE

Note that the line printf("#ifdef VAR_SET_TO_FALSE\n"); is compiled while the line printf("#if VAR_SET_TO_FALSE\n"); is not. The first one is compiled, because VAR_SET_TO_FALSE is defined, even though its value is false.



回答4:

If I'm reading your question correctly the title is misleading, it should be

Is #if MACRO equivalent to #ifdef MACRO?

They are not equivalent but they can (and often are) both used to specify binary modes which are either on or off. The choice is, in my opinion, a matter of personal preference.

You are using the first option and either have

#define verbose true

or

#define verbose false

and then check the mode using either

#if verbose

or

#if !verbose

Actually, I would recommend you use either TRUE or 1 instead of true and either FALSE or 0 instead of false, because true and false, are (or can be) C/C++ values and the pre-processor doesn't have access to C/C++ values.

Anyway, the other common way to specify binary modes is to either define the flag or leave it undefined in which case you can have either

#define verbose any thing (including nothing) goes here

or leave out the #define.

and then you can test whether the flag is defined, either with

#ifdef verbose

or its equivalent

#if defined(verbose)

NOTE: In this case, you are not testing the value of the flag you only need to test whether it is defined.

If it is more convenient you can also test whether the flag is undefined with either

#ifndef verbose

or its equivalent

#if !defined(verbose)


回答5:

If we rack our brains enough, we can come up with a difference. But it is obscure and involves undefined behavior, so it is of no consequence if all we care about is whether the code is strictly conforming to ISO C.

The #if defined ... form is susceptible to behaving differently if previously a #define defined ... macro was processed. In the ISO C99 standard it was written, in regard to the #if and #elif directives:

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.

No requirement is given that the defined unary operator be recognized and protected from being treated as a macro; it is just one of the "preprocessing tokens that will become the ... expression". The defined operator is recognized at this stage only for the purposes of protecting its argument from expansion.

If the definition of define as a macro is simply permitted to stand, and occurrences of defined are subsequently replaced (including in the arguments of #if preprocessing directives) thus interfering with #if defined, while not affecting #ifdef.

Perhaps this area of the language was tightened up since C99.