C ‘assert’: Design Invariants With Macros

Using Assertions for Robust Software Development

c assertDuring the course of the software development in C, there are deliverables for customers and deadlines, but developers will find bugs and issues in their design or execution, or both. How do software developers build programs and maintain it across these years with changing feature requests? On a simpler level, how do change software, code – programs, and algorithms – without losing the original functionality?

Software development learns from a maxim, ‘History repeats itself, if you don’t learn from your mistakes‘. In this blog post, you will learn about writing a simple C program and updating it as requirements change all the time using unit tests to capture this behavior. This could be your beginning, exciting baby steps to advanced graphics programming, and game development!

Meet the Assert Macro

If you a beginning C user, you may benefit from using the C compiler in small steps. In Windows, you can use the Mingw GNU tool chain, Borland C/C++ compilers or Microsoft Visual Studio, or the shell in Linux. Start by typing in the shell,

$ gcc --version

and you should see the following output, then you are ready to dive into C development.

gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

Copyright (C) 2011 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO

warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Follow along by typing into a file these lines of code and save it as ‘assert_true.c’

#include <stdio.h>

#include <assert.h>


typedef unsigned char bool;

bool TRUE = 1;
bool FALSE = 0;


int main() {
    assert( TRUE );
    assert( 1 + 1 ) ;
    assert( 1 + 1 > 0 );
    assert( 1 + 1  –  4 ) ; 
}

To compile and execute the program you can run the commands,

$ gcc assert_true.c -o assert_true
$ ./assert_true

And you can see no real output except the next prompt, which means you code did not trigger any assertion faliures. Lets try again with another program, and save it as ‘assert_fail.c’

#include <stdio.h>
#include <assert.h>

typedef unsigned char bool;

bool TRUE = 1;
bool FALSE = 0;


int main() {
    assert( FALSE );
    assert( 1 - 1 ) ;
    assert( 1 - 1 > 0 );
    assert( 1 - 1  -  4 > 0 ) ; 
}

To compile and execute the program you can run the commands,

$ gcc assert_fail.c -o assert_fail
$ ./assert_fail
assert_fail: assert_fail.c:10: main: Assertion `FALSE' failed.

Aborted

Your empirical experiments have shown you something about assert macro; i.e. on True evaluation of expression assert is quiet, on false evaluation of the statement it triggers the assert_fail and aborts the program execution.

Syntax of Assert Macro

The assert is a macro in C language. To include the assert function in your program you can add the header file definition,

#include <assert.h>

where the assert macro evaluates the expression and aborts execution when the said expression has a false value in C. If the expression evaluates to NULL, false, 0, then assertion is said to have occurred. Only calls like setjmp, and longjmp and atexit have a change of completing after the assert() has triggered. For more details read the manual page on Linux for assert function.

	$ man assert 

should bring up a page like,

 

ASSERT(3)                  Linux Programmer's Manual                 ASSERT(3)


NAME

       assert - abort the program if assertion is false


SYNOPSIS

       #include <assert.h>


       void assert(scalar expression);


DESCRIPTION

       If  the  macro  NDEBUG  was  defined  at the moment <assert.h> was last

       included, the macro assert() generates no code, and hence does  nothing

       at all. 

Program Design

Programmers use the assert macro to raise errors to catch unexpected behavior of their code. For example, if you wrote a program to calculate the volume of a solid, or area of a polygon, you can include an assertion that the volume, or area, respectively should not be zero; i.e. assert area > 0

Examples – Using Assertions in Factorial Function

Factorial of a number, N, is defined to be the product of numbers from 1 to N; i.e. N! = 1*2*3* … N. Clearly a straightforward way to calculate factorial is using a for-loop, but we prefer to use a recursive definition. This recursive form is equivalent, and accurate, mathematical definition of factorial function is using the notation; i.e. N! = (N-1)!*N. Here we can use the assert macro to ensure the result of factorial is always positive.

Clearly a way of writing this as a program in iterative and recursive ways would be,

#include <stdio.h>
#include <assert.h>

typedef unsigned char bool;

bool TRUE = 1;
bool FALSE = 0;

/* recursive way of writing factorial */

int fact( int n ){
    if ( n == 0 ) {
        return 1;
    }
    return fact( n - 1)*n;
}


int main() {
      int fact_val;
      int i;

      for( i=0; i < 10; i++ ) {       	     
       	 fact_val = fact(i);
         /*factorial is always non-zero*/
       	 assert( fact_val > 0 );
         printf("%d! = %d\n",i,fact_val);
     }

     return 0;
}

Running the Program

You can download C package for your platform from the source website, C.org, and run the tests and programs as, $gcc fact_assert.c -o fact_assert && ./fact_assert, is the command to interpret the code and then run the program

0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880

Bugs and Fixes

There are various bugs in the function in the program few of which are,

  1. Function does blows up with negative inputs. You need to have include guards or asserts.

  2. Numerical overflow for large input n

It is left as an exercise to the reader to update the code for the following and run it on the C interpreter to see a message which shows the 2 unittest have passed, and happy ‘OK’ message is printed on screen.

Summary

Software developers use assertions to enforce invariants in the design of programs, and testing those programs against regression. The C assert macro is one of key tools to enforce invariants in code, and in testing enabling users and developers of programs to progress without regression. Learn more about regression testing and software design. Learning C can lead you to other things like programming your iPhone, and more complex projects.