C++ #if , #elif ,#else ,#endif preprocessor conditional directives

In the last post we have seen ‘#include’ directives and it’s function seem to be very specific-to include the header’s file content.In this post let us discuss the #if , #elif ,#else ,#endif directives also known as preprocessor conditional directives.

Link: C++ #include directive

As the names suggest they are use as conditional statements.They can exert authority over certain codes that should be made available for compilation in some specific compiler or platform and which should not on other cases.They are known for their conditional property but their uses is not limited to exerting condition,it can vary depending on how you implement them.Before we see some of their specific uses let us see the proper syntax that should be applied while using them and which programming entity goes with them.

If you look at the names of the directives #if , #elif , #else they resemble with the execution control statements if(),elseif() and else().Fortunately their behavior are also similar.However,the statement #endif on the other hand holds no significant properties and it simply signify the end of #if directives(or region).

Like the execution control statements the conditional directives require a token that gives either true or false value and depending on that the code or macros belonging to the directive is executed.Consider the simple program below.

#include <iostream>

using namespace std;

/*assign _NUMERAL to 90 and _TEST_VALUE to 100 */
#define _NUMERAL 90 
#define _TEST_VALUE 100 

int main( )
{
//check if _NUMERAL is not 0
#if _NUMERAL 
  cout<< _NUMERAL << endl ;
//Ending the #if region
#endif 


#if _NUMERAL >= _TEST_VALUE
  cout<< _NUMERAL << “>=” << 100 << endl;

#elif _NUMERAL <= _TEST_VALUE
  cout<< _NUMERAL << ” <=” << 100 << endl ;

#else
  cout<< _NUMERAL
//End of code
#endif 

#if defined(_NUMERAL)
  cout<< _NUMERAL << endl ;
#endif

cin.get( );
return 0 ;
} 

The output is,

90
90 <= 100
90

The macro _NUMERAL is interpreted as true if it is not 0,hence the first #if directive outputs the _NUMERAL value.

In the third #if statement defined() is used to check whether the macro _NUMERAL has been exist.Using defined() does not check what value is assigned to the macro and so it does not check for true or false,it simply checks whether the macro _NUMERAL exist or not.If it exist it will be taken as true otherwise false.

Consider another code example.

#define _NEW

int main( )
{
//error!! _NEW is not assigned any value
#if _NEW 
  cout<< _NEW ;
#endif

// Work absolutely fine
#if defined(_NEW)
  cout<< “_NEW defined \n” ;
#endif

//Work fine
#if defined( _DUDE)
  cout<< “_DUDE” ;
#endif

/*works fine,this macro come with the Code::blocks compiler so it’s true if you are using it */
#if defined(__GNUC__)   
  cout<< __GNUC__ ;
#endif

cin.get( ) ;
return 0 ;
} 

The line ‘#if _NEW ‘ is an error because _NEW is defined but no value is assigned to it so true or false cannot be determined.

The line ‘#if defined(_NEW)’ is fine because although _NEW does not exist defined(_NEW) will return false hence the code under #if is not executed.

There are many macros like __GNUC__ which is a compiler specific macros defined only for the GNU GCC compiler, Visual Studio also have their own macros defined for it’s compiler,you can Google up to find more such macros and their uses.

Next let’s see some of the specific uses of conditional directives in C++.


i)Choosing a compatible code for a specific compiler

Suppose you want to make a library(in C++) that can be compiled using both GNU GCC compiler and Visual studio compiler or more say you want to choose over which macros to define and which to not when using a specific compiler.The solution is simple,you will use conditional directives to choose between the compiler and define the required macros.The code will look something like this.

#if defined(__cpluspluc)   ///this macros is defined for all C++ compiler
 #if defined(__MINGW32__)   ///__MINGW32__ is defined only in GCC compiler
   //defined your macros or include your code here

 #elif defined(_MSC_VER)   ///_MSC_VER is defined only in Visual Studio compiler
  //defined your macros or include your code here
#endif

The implementation is simple here:

i)check for macros defined only in the specific compiler and execute the code for that compiler.If you are compiling in GCC compiler __MINGW32__ macro is already defined(and is defined only in GCC compiler),so the expression “defined(__MINGW32__)” renders true and the code or macros under that #if statement is executed.The same happened when the file is compiled in Visual Studio,since _MSC_VER macro is defined only in VS compiler this time the expression “defined(_MSC_VER)” becomes true and the code under #elif directive is compiled.

The compilation need not be limited for just two compilers you can extend to other compiler by using the suitable macros defined only for that compiler.There is a more detail explanation for using libraries with different compiler here http://gernotklingler.com/blog/creating-using-shared-libraries-different-compilers-different-operating-systems/


ii)Commenting out a section of code

If you have written a library,sometimes certain situation compels you to abandon certain parts of your code or you may want to make some part of the code available in the next version of the library.In this case deleting the whole code seems needless,so instead what you would prefer is commenting out the code.This is a better option than deleting because you wouldn’t have to rewrite the whole code again in the future.The simplest way for doing this in your library file or any other file is using the conditional directives #if.

#if 0   ///this is false so the code is not executed.

//your code here

#endif 

Since 0 will always render false the code under the #if directive is always left out when compiling the program.