SunQuest
 
       C++
  Home arrow C++ arrow Page 4 - C++ Preprocessor: The Code in the Middle
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Dedicated Servers  
Actuate Whitepapers 
Moblin 
IBM® developerWorks 
Sun Developer Network 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
C++

C++ Preprocessor: The Code in the Middle
By: J. Nakamura
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 36
    2005-10-31

    Table of Contents:
  • C++ Preprocessor: The Code in the Middle
  • String Substitution
  • String Manipulation
  • Conditional Compilation
  • Inclusion Guards
  • Predefined Macros

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT

    Stay one step ahead of the competition. Evaluate and give feedback on some of the hottest web development tools on the market today. Make your opinion heard! Click Here

    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.

    More C++ Articles
    More By J. Nakamura


       · Hi, C++ coders. Thanks for reading Dev Articles. Please let us know what you think...
     

    C++ ARTICLES

    - Large Numbers
    - Dijkstra`s Shunting Algorithm with STL and C...
    - Brief Introduction to the STL Containers
    - The Standard Template Library
    - Templates in C++
    - C++ Programmer Alerts
    - C++ Programming Tips
    - First Steps in (C) Programming, conclusion
    - First Steps in (C) Programming, continued
    - First Steps in (C) Programming, introduction
    - C++ Preprocessor: Always Assert Your Code Is...
    - C++ Preprocessor: The Code in the Middle
    - Programming in C
    - Temporary Variables: Runtime rvalue Detection
    - Temporary Variables: Chasing Temporaries Away







    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 4 hosted by Hostway