C++
  Home arrow C++ arrow Page 4 - C++ Preprocessor: Always Assert Your Code ...
IBM developerWorks
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: Always Assert Your Code Is Right
By: J. Nakamura
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 43
    2005-11-07

    Table of Contents:
  • C++ Preprocessor: Always Assert Your Code Is Right
  • Implementing Assert
  • Implementing a Simplified Assert
  • Refining Assert

  • 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: Always Assert Your Code Is Right - Refining Assert


    (Page 4 of 4 )

    The simplest solution is to just expand the assert macro and make it accept a message as well as a condition:

    #ifndef NDEBUG
    # define ASSERT( isOK, message ) \
     if ( !(isOK) ) { \
      (void)printf(“ERROR!! Assert ‘%s’ failed on line %d “ \
       “in file ‘%s’\n%s\n”, \
          #isOK, __LINE__, __FILE__, #message); \
       __asm { int 3 } \
      }
    #else
    # define ASSERT( unused, message ) do {} while ( false )
    #endif

    Again the stringize operator helps us to stuff the message we want into the printf statement. We could call it a day now, but I am a very lazy coder… I do not want to be forced to put messages into the assert, sometimes I just want to assert.

    Of course it is possible to write an ASSERT(condition) and an ASSERTm(condition, message) macro, but did I mention I am a forgetful coder too? I’d much rather have a single ASSERT statement that can do both.

    The first thing that comes to mind is the fact I could do this easily with a function:

    void MyAssert(bool isOK, char const *message=””) {
     if ( !isOK ) {
      (void)printf(“ERROR!! Assert ‘%s’ failed on line %d “
       “in file ‘%s’\n%s\n”,
       __LINE__, __FILE__, message);
      __asm { int 3 } \
     }
    }

    So maybe if I declared another function:

    void NoAssert(bool isOK, char const *message=””) {}

    And then defined assert as:

    #ifndef NDEBUG
    # define ASSERT MyAssert
    #else
    # define ASSERT NoAssert
    #endif

    While this seems like a quick solution, I have completely lost my extra debug information! The line information is the same now for every assert… oh… the compiler substitutes __LINE__ with the actual line number it is compiling at that moment, and since we are making a function call – all line numbers lead to the MyAssert function!

    Alexandrescu demonstrates a great way around this problem [Alexandrescu]. (It is also a great article showing how you can take assertions to a higher level after this one, by making them throw exceptions!)

    #ifndef NDEBUG
    #define ASSERT \
     struct MyAssert { \
     MyAssert(bool isOK, char const *message=””) { \
      if ( !isOK ) { \
       (void)printf(“ERROR!! Assert failed in “ \
        “file ‘%s’\n%s\n”, __FILE__, message); \
        __asm { int 3 } \
       } \
      } \
     } myAsserter = MyAssert
    #endif

    For some reason my Visual C++ 7.1 compiler will not accept the __LINE__ macro next to the __FILE__ macro in the code above. The strange thing is that the __FILE__ macro works fine, but with __LINE__ it complains:

    error C2065: '__LINE__Var' : undeclared identifier

    It is never easy, but I do not want to give up at this point. Since the macro is expanded as a single line into the place where we are calling it, and since the compiler apparently has no objection to me assigning __LINE__ as a default parameter in a constructor, let's try again:

    #ifndef NDEBUG
    #define ASSERT \
     struct MyAssert { \
     int mLine; \
     MyAssert(int line=__LINE__) : mLine(line) {} \
     MyAssert(bool isOK, char const *message=””) { \
      if ( !isOK ) { \
       (void)printf(“ERROR!! Assert failed on “ \
        “line %d in file ‘%s’\n%s\n”, \
        MyAssert().mLine, __FILE__, message); \
       __asm { int 3 } \
      } \
     }\
     } myAsserter = MyAssert
    #endif

    Now that we have our line information back, we are nearly there; as soon as we add a second assert, the compiler complains that we are redefining the struct MyAssert! If only we could keep the struct declaration local… and again Alexandrescu shows us how [Alexandrescu]:

    #ifndef NDEBUG
    #define ASSERT \
     if ( false ) {} else struct LocalAssert { \
      int mLine; \
     LocalAssert(int line=__LINE__) : mLine(line) {} \
     LocalAssert(bool isOK, char const *message=””) { \
      if ( !isOK ) { \
       (void)printf(“ERROR!! Assert failed on “ \
        “line %d in file ‘%s’\n%s\n”, \
        LocalAssert().mLine, __FILE__, message); \
       __asm { int 3 } \
     } \
     } myAsserter = LocalAssert
    #else
    #define ASSERT \
     if ( true ) {} else struct NoAssert { \
     NoAssert(bool isOK, char const *message=””) {} \
     } myAsserter = NoAssert
    #endif

    There is a lot of fun to be had with macros and sometimes it is possible to create the wildest incantations with them [Niebler/Alexandrescu]. I hope you are convinced that despite the fact that they can be considered evil, there is something magical about them as well.

    As a final example I will show you how to create personal and customizable debug streams in the next article… all with macros.


    References

     [STL] – The Standard Template Library

    < comes standard with your compiler but this one is very portable>

    http://www.stlport.org

    [BOOST] – Boost C++ Libraries

    http://www.boost.org

    [ACE] – The ADAPTIVE Communication Environment

    http://www.cs.wustl/edu/~schmidt/ACE.html

    [Niebler] – Eric Niebler

    “Conditional Love: FOREACH Redux”

    http://www.artima.com/cppsource/foreach.html

    [Alexandrescu] – Andrei Alexandrescu

    Assertions

    http://www.cuj.com/documents/s=8248/cujcexp2104alexandr/


    DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware.

       · ‘this code won’t be used the next millennium, two digits are fine’Yo, C++...
       · I have been working on C,C++ for some time, and have been relying on conditionals...
       · This code doesn't compile in Visual Studio 7.1.error C2440: 'type cast' : cannot...
       · At work we are now using the assertions of ModAssert. Over the past two months we...
       · Assert may suffice for ivory tower programming; but it's no substitute for a well...
     

    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


    Iron Speed





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