Home arrow C++ arrow Page 4 - C++ Preprocessor: The Code in the Middle
C++

C++ Preprocessor: The Code in the Middle


In this article, we examine instructions given to the preprocessor and see how they are used in general. The preprocessor handles your code before the compiler interprets it. If you have been wondering just what the preprocessor is used for, this article explains.

Author Info:
By: J. Nakamura
Rating: 4 stars4 stars4 stars4 stars4 stars / 40
October 31, 2005
TABLE OF CONTENTS:
  1. · C++ Preprocessor: The Code in the Middle
  2. · String Substitution
  3. · String Manipulation
  4. · Conditional Compilation
  5. · Inclusion Guards
  6. · Predefined Macros

print this article
SEARCH DEVARTICLES

C++ Preprocessor: The Code in the Middle - Conditional Compilation
(Page 4 of 6 )

One more way to use ‘#define’ is to declare that a particular token is defined. This token can be used in combination with the precompiler commands “#if”, “#elif”, “#else” and “#endif” to test whether or not the preprocessor should include the code that follows the directive.

To see if a token is defined you use “#if defined” or “#elif defined” and to see if a token is not defined you use “#if !defined” or “#elif !defined”.  You can use the logical ‘&&’ and ‘||’ operators to concatenate instructions.

If for some reason you would like to remove a token from the table the preprocessor stores it in, you can undefine it with ‘#undef’.

A common use is to define a token DEBUG when compiling non-optimized code. If you use the Microsoft Developer Environment, a token _DEBUG is automatically defined for your project’s Debug configuration.

#include <stdio.h>
#define MYDEBUG
static int const MAX_STR_LEN 80;

int main(int argc, char const *argv[]) {
 int anArray[MAX_STR_LEN];
 for (int idx=0; idx<MAX_STR_LEN; ++idx) {
#ifdef MYDEBUG
  (void)printf(“%d “, idx);
#endif
  anArray[idx]=0;
 }
}

First the precompiler runs into the ‘#include’ instruction, so it reads the ‘stdio.h’ file (which it can find using your project’s header include path) and pastes it into the temporary source file it is going to feed to the compiler. Next it encounters the ‘#define’ instruction and it stores the MYDEBUG token in a lookup table.

Finally when it comes across the ‘#ifdef’ instruction it checks whether MYDEBUG was defined in its lookup table and when this is the case it will continue to write everything it finds until the ‘#endif’ instruction into an intermediate source file.

When it cannot find the token it will check whether the next instruction is another comparison “#elif”, tells it to follow that route otherwise “#else” or that the end of the block was reached “#endif”.

If you look at the macros used to configure STL-Port (STL), Boost (BOOST) or ACE (ACE), things can become rather complex. Handy as macros can be, they do not make the code easer to read (and thus understand). Here is a snippet from the boost thread class:

class BOOST_THREAD_DECL thread : private noncopyable {
 ...
private:
#if defined(BOOST_HAS_WINTHREADS)
    void* m_thread;
    unsigned int m_id;
#elif defined(BOOST_HAS_PTHREADS)
private:
    pthread_t m_thread;
#elif defined(BOOST_HAS_MPTASKS)
    MPQueueID m_pJoinQueueID;
    MPTaskID m_pTaskID;
#endif
    bool m_joinable;
};

Because the macros are obfuscating which variables are needed here (because different platforms offer different facilities), it is easy to overlook that on Linux this would filter into:

private:
private:
    pthread_t m_thread;
    bool m_joinable;
};

When you want your code to be portable across different platforms, preprocessor macros will help you to maintain a single source tree. Unfortunately your eyes will have to deal with all possibilities, instead of the single one that your compiler might be choking on.

When there are so many trees it becomes difficult to see the forest.


blog comments powered by Disqus
C++ ARTICLES

- Intel Threading Building Blocks
- Threading Building Blocks with C++
- Video Memory Programming in Text Mode
- More Tricks to Gain Speed in Programming Con...
- Easy and Efficient Programming for Contests
- Preparing For Programming Contests
- Programming Contests: Why Bother?
- Polymorphism in C++
- Overview of Virtual Functions
- Inheritance in C++
- Extending the Basic Streams in C++
- Using Stringstreams in C++
- Custom Stream Manipulation in C++
- General Stream Manipulation in C++
- Serialize Your Class into Streams in C++

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials