Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C++ (http://www.go4expert.com/articles/cpp-tutorials/)
-   -   ASSERTs in C++ (http://www.go4expert.com/articles/asserts-in-cpp-t18309/)

Mridula 2Jul2009 18:36

ASSERTs in C++
 

Introduction



This article talks about ASSERTs usage and customizing our own ASSERTs.

Background



Asserts are to catch implementation errors. The developer can document all the assumptions made on the his/her program, by using ASSERTs. If you have used asserts in your code and if it triggers, then you can know, there is a problem in your code and needs to be solved. And thus ASSERTs are to find bugs in your code.

These Asserts are available only for Developer loads or Debug loads. And are completely removed from Customer binaries or Release loads and so no issue of increase in the size of binary version nor the issue with the degrade in the performance of the application that is shipped to Customer.

Assert is a macro provided by compiler and it returns True if the expression provided to it evaluates as True Or it returns False and abort the program, if the expression provided to it evaluates as False . And thus helps developer to find bugs beforehand. it is available in assert.h header file.

When to use ASSERTs

Developers should make it a practice to use Asserts wherever it is needed to test :

1. Validity of function arguments before using them
2. Validity of a pointer before using it
3. Testing any condition that you think, Must be True i.e. checking the values of a
variable at some point in code, checking the expected range at some point etc. .

Customizing our own ASSERTs

Well, we can customize our own Assert to display a better informative/formated error messages and end the application in a proper way before aborting. It means releasing any held semaphores, deleting something or logging required infromation to files etc instead of ending the system abruptly. So this would help later debuging the code and fix the recorded problem.

So, if you encounter a core/trap, think whether this core can be caught using our own customised ASSERT, before fixing it. This helps you next time when the same bug encounters in future testing like integration testing etc with a better explained message and correct position to analyze the bug, when that Assert triggers.

Here is a sample code for MY_ASSERT Macro and it's usage:

The code



Code: Cpp

#define DEBUG

#include<iostream.h>

#ifndef DEBUG
  //do nothing
#else
  #define MY_ASSERT(x) \
    logMsg(x, #x, __FILE__, __LINE__)
#endif

bool logMsg(bool x, const char *msg, char* file, unsigned int line)
{
  if( false == x)
  {
    //do that extra logging information to a file etc.
    cout<<"On line " <<line<<":";
    cout<<" in file " <<file <<":";
    cout<<" Error !! Assert "<<msg << " failed\n";
    abort();
    return (true);
  }
  else
  {
    return(true);
  }
}

int main()
{
  int x;
  x = 5;

  cout<<"Checking First assert...\n";
  MY_ASSERT(5==x);

  cout<<"Checking Second assert...\n";
  MY_ASSERT(x!=5);

  cout<<"Done...\n";
 
  return(0);
}

output:

Checking First assert...
Checking Second assert...
On line 37: in file assert.cc: Error !! Assert x!=5 failed
Abort (core dumped)


Here MY_ASSERT macro is valid only if DEBUG flag is on. Else, it is nothing in customer binary as shown above.

When Not to USE ASSERTs

It is bad to use Asserts to handle conditions that application does not have in it's control like out-of memory conditions, unable to open the file etc., which can occur even in Customer loads as well.

Example for bad use of Assert:

The code



Code: Cpp

Base *bptr = new Derived;
MY_ASSERT(bptr); //incorrect usage of MY_ASSERT
bptr->doSomething();


Error Handling in Customer Binaries

If developer anticipates the ASSERTs that are introduced in code, might also come in customer load, then he/she can handle it through error handling techniques to take care or control bugs even in Customer loads.

For example:

The code



Code: Cpp

void func(unsigned int range)
{
  MY_ASSERT(0 < range < 100); //this assert will not be there in Customer Binary, so
  if (0 > range)
  {
    range = 0;
  }
}


Here, the method "func" might receive the input "range" as less than 0 as well from external user, in that case, since in customer load, ASSERT would have been removed and so as part of error handling, we can modify the value of variable "range" to "0" and hence prevent any future bugs.

ASSERTs in Customer Binary

To handle extreme cases like,
To detect improper/unreachable external conditions in the application Or
Some part of the code, which is never executed like default case in switch statement as exaplined in example code below etc,

We can go for special ASSERT Macros that can be there even in Customer Binaries as well.

Here is a customized Macro called MY_RELEASE_ASSERT which is avaiable for both Developer loads and Customer loads as well.

The code



Code: Cpp

#define DEBUG

#include<iostream.h>

// here is a DEBUG ASSERT

#ifndef DEBUG
  //do nothing
#else
  #define MY_ASSERT(x) \
    logMsg(x, #x, __FILE__, __LINE__)
#endif

bool logMsg(bool x, const char *msg, char* file, unsigned int line)
{
  if( false == x)
  {
    cout<<"On line " <<line<<":";
    cout<<" in file " <<file <<":";
    cout<<" Error !! Assert "<<msg << " failed\n";
    abort();
    return (true);
  }
  else
  {
    return(true);
  }
}

// here is a Customer Binary ASSERT

#define MY_RELEASE_ASSERT(x) \
    logMsgForRelase(x, #x, __FILE__, __LINE__)

bool logMsgForRelase(bool x, const char *msg, char* file, unsigned int line)
{
  if( false == x)
  {
    cout<<"On line " <<line<<":";
    cout<<" in file " <<file <<":";
    cout<<" Error !! Assert "<<msg << " failed\n";
    abort();
    return (true);
  }
  else
  {
    return(true);
  }
}

int main()
{
  int x;
  x = 5;

  switch (x)
  {
    case 0:
    {
      //valid case, do something
      cout<<"Checking First assert...\n";
      MY_RELEASE_ASSERT(5==x);
      break;
    }

    case 1:
    case 2:
    {
      //valid case, do something
      cout<<"Checking Second assert...\n";
      MY_RELEASE_ASSERT(x!=5);
      break;
    }

    default:
    {
      //should never reach here
      MY_RELEASE_ASSERT(false);
    }
  }

  return(0);
}

output:

On line 74: in file assert1.cc: Error !! Assert false failed
Abort (core dumped)

//infact this should never happen !!
 


Here you can notice the macro MY_RELEASE_ASSERT is not wrapped with any conditinal flags and so available for both Debug and Customer loads.

Bottom Line:-
If you are unfamilier with ASSERTs, you should start using them now onwards, it really helps finding, analysing, debugging and fixing bugs beforhand in your DEBUG loads!!

thanks
Mridula.

shabbir 2Jul2009 20:43

Re: ASSERTs in C++
 
I really like your articles and vote for the same as well.

Mridula 3Jul2009 10:05

Re: ASSERTs in C++
 
Many many thanks Shabbir.
I am feeling as if I have won the prize !! This is enough to keep going.

many thanks
mridula.

SaswatPadhi 3Jul2009 12:19

Re: ASSERTs in C++
 
Quote:

Originally Posted by Mridula (Post 51180)
Many many thanks Shabbir.
I am feeling as if I have won the prize !! This is enough to keep going.

Yeah, when the admin himself likes your article, you are really really lucky !!!!!! :)

naimish 6Jul2009 15:18

Re: ASSERTs in C++
 
yeah...one of the lucky :)

LenoxFinlay 18Jul2009 10:26

Re: ASSERTs in C++
 
If the argument expression of this macro with functional form compares equal to zero, a message is written to the standard error device and abort is called, terminating the program execution. The specifics of the message shown depend on the specific implementation in the compiler, but it shall include: the expression whose assertion failed, the name of the source file, and the line number where it happened. A usual expression format is:
Assertion failed: expression, file filename, line line number

shabbir 3Aug2009 14:34

Re: ASSERTs in C++
 
Nominate this article for Article of the month - Jul 2009

mayjune 3Aug2009 19:34

Re: ASSERTs in C++
 
congrats...

shabbir 16Aug2009 13:21

Re: ASSERTs in C++
 
Vote for this article for Article of the month - July 2009


All times are GMT +5.5. The time now is 22:06.