Coding Assertively (with Assertions)

By Anton Gerdelan

What Are Assertions

Assertions are a basic run-time test for program state correctness, and can save you a lot of time. If given an expression that resolves to false, an assertion prints the file name and line number of the failing call, and raises SIGABRT. This deliberately crashes the program. If the expression resolves to true then it does nothing.

int counter = 100;
assert( counter < 100 ); // this will resolve to false and fail
bool return_success = some_function();
assert( return_success );

Why Use Assertions

How and When We Can Use Assertions

In C or C++:

A good strategy is to test the inputs of each function for validity eg NULL pointers, or check if values used to index arrays will be within bounds. As a rule of thumb, any code where you think “Ah, if this value ever gets in here and is negative/NULL/too large/false, it will break.” is a good place to guard with an assertion. It might pass for now, but it can catch a breaking change to the code at a later date.

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

/* trivial function to change a character in a length-10 char array to
the null terminator
str - must be a string of length 10 and cannot be a NULL pointer
str_index - must be between 0 and 9, inclusive */
void my_str_truncate( char* str, int str_index ) {
  // crash if str was NULL and then check the length is not too long
  assert( str && strlen( str ) < 10 );
  // crash if value was outside of allowed range
  assert( str_index >= 0 && str_index < 10 );

  str[str_index] = '\0';
}

int main() {
  char name[10];
  strcpy( name, "anton" );
  my_str_truncate( name, 3 );
  // should print "ant"
  printf( "truncated: %s\n", name );
    return 0;
}

You may also use assertions to unit test for correct outputs of your functions in a test program:

#include <assert.h>

/* trivial function to add two integers */
int my_adder( int a, int b ) {
  return a + b;
}

void run_tests() {
  const int a_inputs[3]         = { 0,  100, -100 };
  const int b_inputs[3]         = { 0, -200,  200 };
  const int expected_outputs[3] = { 0, -100,  100 };
  for ( int i = 0; i < 3; i++ ) {
    int result = my_adder( a_inputs[i], b_inputs[i] );
    assert( expected_outputs[i] == result );
  }
}

Tips and Common Mistakes

For best effect assertions should be used in combination with other testing and debugging tools. When combined with an interactive debugger, a back-trace, and logging and printing of errors and warnings, a programmer can very rapidly diagnose, follow, and reason about problems in even very complex code with many people contributing to it.