|
Assert is a macro used for debugging a C program. If the assert fails, a message prints out indicating the exact failure, and then the program exits, usually producing a core dump. Using the macroIn a large program, you can get to a point where you know that the program should be in a certain state. For debugging purposes, you want to double-check to make sure that it actually is in that state. For example, let's say you are writing a function that will search a subset of an array for a particular value. int subsrch(int start, int end, int *arry, int val)
Subsrch() searches the array arry from the index start to the index end for the value val. Subsrch() returns either the index at which it finds the value or -1 if the value was not found.
When the Subsrch() function is called, the parameters must be correct. You could examine every call to subsrch() in your program to make sure it is called correctly, but if there are several hundred of them, this could be time prohibitive. You could also write a bunch of if statements at the beginning of the function, but that would make the function very hard to read and very slow, even when you aren't debugging it. This is where the assert statement can help. You can place a number of assert statements in your function to verify that the arguments are correct. For example, you can't search the array if it doesn't exist. assert(arry != NULL);
This statement says that at this point in the code, arry must not be NULL. If it is, then an error prints to stderr, and the program aborts, (usually) producing a core file. The message that prints is very informative: Assertion failed: arry != NULL, file foobar.c, line 9 It tells you exactly what assertion failed and where to find it. With a core dump, you can easily use a debugger to get a stack trace that tells you who called the function with a NULL array. Because assert is a macro, it has advantages over writing if statments. First, you don't have to use them for production (non-debug) code. If the define NDEBUG is set, then the assert macro evaluates to an empty statement: it does nothing. You can have all the debugging assert statements you like and it won't have any impact on the final, non-debug, program. The argument to an assert statement can be any conditional statement that evaluates to true or false. assert( (start >= 0) && (end >= 0) ); assert(start <= end);
There are many more uses for assert besides just checking parameters. For example, when you get to the end of a function, you know that you either found the value between start and end, or you have to return -1 to indicate that it was not found. assert( (retval == -1) || ( (retval >= start) && (retval <= end) ) );
Now you can be sure that no matter what changes you make to how the function works, the return value is correct. There are two things to note about assert(). First, it is defined in /usr/include/assert.h, so you have to #include <assert.h> in any source file where you want to use it. Secondly, because assert() is a macro, beware of using conditionals with side-effects. assert(i++ > j); /* Not Good */
The above statement might work just fine while debugging, but when you compile with -DNDEBUG, the i++ will not execute. Only use conditionals without side-effects in an assert statement. #include <stdlib.h>
#include <assert.h>
int subsrch(int start, int end, int *arry, int val)
{
int retval = -1;
int i;
assert(arry != NULL);
assert( (start <= 0) && (end >= 0) );
assert(start <= end);
for (i=start; i <=end; i++)
{
if (arry[i] == val)
{
retval = i;
break;
}
}
assert( (retval == -1) || ( (retval >= start) && (retval <= end) ) );
return retval;
}
|