Jump to content


Extreme Debugging - Smart asserts


4 replies to this topic

#1 bladder

    DevMaster Staff

  • Members
  • PipPipPipPip
  • 1057 posts

Posted 12 September 2004 - 01:18 AM

I read this article a while back about using recursive preprocessing to enhance the capabilities of an assertion. The article was written by one Andrei Alexandrescu, the author of Modern C++ Design. Here's a direct link to the article that explains the recursive process in details, and the following is the full and IMO minimal implementation of it. This is an excellent tool to have with you. It greatly increases the information you can get out of an assertion.

// Header file.
#ifndef CUSTOM_ASSERT_H_
#define CUSTOM_ASSERT_H_

#include <string>
#include <fstream>

#ifndef __FUNCTION__
#define __FUNCTION__ "???"
#endif

#ifndef __FILE__
#define __FILE__ "???"
#endif

#ifndef __LINE__
#define __LINE__ 0
#endif

class CustomAssert
{
    std::string m_Expression;
    std::string m_Filename;
    int m_Line;
    std::ofstream m_File;
    int m_Count;

public:
    
    CustomAssert& CUSTOM_ASSERT_A;
    CustomAssert& CUSTOM_ASSERT_B;

    CustomAssert();
    ~CustomAssert();

    template< typename T > CustomAssert& Print( const char* str, T val )
    {
        m_File<< "<font face="verdana" size="1" color="#DDDDFF">    "<< str;
        m_File<< ": <font color="#dd88ff">"<< val<< "</font></font><br>";
        return *this;
    }

    CustomAssert& Msg( const char* str );

    void Break();

    CustomAssert& operator () ( const char* expr, int line, 
                                const char* func, const char* file );
    
}; 

extern CustomAssert g__SmartAssert__;


#define CUSTOM_ASSERT_A(x) CUSTOM_ASSERT_OP( x, B )
#define CUSTOM_ASSERT_B(x) CUSTOM_ASSERT_OP( x, A )

#define CUSTOM_ASSERT_OP( x, next ) CUSTOM_ASSERT_A.Print( #x, (x) ).CUSTOM_ASSERT_ ## next


#ifdef _DEBUG

#define Assert( expr ) 
    if( (expr) ); 
    else g__SmartAssert__( #expr, __LINE__, __FUNCTION__, __FILE__ ).CUSTOM_ASSERT_A 

#else

#define Assert( expr ) 
    if( true ); 
    else g__SmartAssert__( #expr, __LINE__, __FUNCTION__, __FILE__ ).CUSTOM_ASSERT_A 

#endif 

#endif // CUSTOM_ASSERT_H_

// Source file
#include <cassert>
#include "assert.h"

#undef CUSTOM_ASSERT_A
#undef CUSTOM_ASSERT_B


CustomAssert g__SmartAssert__;


CustomAssert::CustomAssert()
    : CUSTOM_ASSERT_A(*this), CUSTOM_ASSERT_B(*this)
{

    m_File.open( "asserts.htm" );
	m_File<< "<html>
    <HEAD>
    <CENTER>
    <TITLE>Asserts</TITLE>
    <H3><font face="verdana"color="ffffdd">Asserts</font></H3>
    </CENTER>
    </HEAD>
    <BODY bgcolor="000000" text="ffffff">
                  <BR><BR>";

    m_File.flush();

    m_Count = 0;
}

CustomAssert::~CustomAssert()
{
    m_File.close();
}

CustomAssert& CustomAssert::operator () ( const char* expr, int line, 
                                          const char* func, const char* file )
{
    m_Expression = expr;
    m_Filename = file;
    m_Line = line;

    static char buffer[32] = {0};

    itoa( m_Count, buffer, 10 );

    m_File<< "<p><b><u><font size="2" face="verdana" color="#ff0000">#";
    m_File<< buffer;
    m_File<< ": "<< expr<< "</font></u></b><br><br>";
    m_File<< "<font size="1" face="verdana"><li>file: <font color="#C1F0FF">";
    m_File<< file<< "</font><br>";
    m_File<< "<li>line: <font color="#C1F0FF">"<< line<< "</font><br>";
    m_File<< "<li>function: <font color="#C1F0FF">"<< func<< "</font><br></font>";

    m_Count++;

    return *this;
}

CustomAssert& CustomAssert::Msg( const char* str )
{
    m_File<< "t"<< "<font size="1" face="verdana" color="#aaff88"><b>msg: </b>";
    m_File<< "<font color="#ffaa88">"<< str<< "</font></font>";
    return *this;
}

void CustomAssert::Break()
{
    m_File.flush();
    _assert( (void*)m_Expression.c_str(), (void*)m_Filename.c_str(), m_Line );

}

The code is readily compilable on msvc. Im not sure of other compilers because Im not sure if they have the same prototype to make an assertion box appear (Called in the Break() function). An example of using the assert follows:

int a = 0;
int b = 3;
int c = 32;
char* str = "string";
float f = 3.45f;
double d = 345.7;

Assert(0 == 1)(a)(B)(c).Msg("Passing ints");
Assert(3 == 4)(f)(d).Msg("Checking floats");
Assert(3 != 3)(str).Msg("Checking string variable");
Assert(0 && 0)(a)(B)(c)(f)(d)(str).Msg("Checking ALL and breaking").Break();


#2 Francois Hamel

    Valued Member

  • Members
  • PipPip
  • 86 posts

Posted 13 September 2004 - 01:33 AM

interresting...
but the style is very ugly :)
I post with style, do you?

http://fhamel.blogspot.com/

#3 davepermen

    Senior Member

  • Members
  • PipPipPipPip
  • 1306 posts

Posted 13 September 2004 - 04:39 AM

i've played around with such code for a while, by myself, too.. i wouldn't have mixed it with the logging directly, thought.. but for the example purpose it's fine..
davepermen.net
-Loving a Person is having the wish to see this Person happy, no matter what that means to yourself.
-No matter what it means to myself....

#4 knackered3

    New Member

  • Members
  • PipPip
  • 19 posts

Posted 15 September 2004 - 12:05 PM

m_File<< "<font face="verdana" size="1" color="#DDDDFF">  "<< str;

doesn't compile out of the box.
you're missing some \ where you have quotes in quotes.

#5 Dia

    DevMaster Staff

  • Administrators
  • 1120 posts

Posted 15 September 2004 - 02:05 PM

knackered: the code initially contained the backslashes, but it seems a bug in the syntax highlighter removed them. This has been fixed, but hasn't been updated on the site yet.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users