assert()

Learning Outcome

Use assert to check invariants and debug.

Introduction

assert() is a macro which tests for conditions which should never occurr in your code.

Applicable subjects

COMP1511, COMP1521, COMP2521, COMP3231


assert

The syntax for assert is:

assert(<expression>);

If expression is false, it aborts the program and displays the error to stderr.

To use assert() place the following at the top of your file:

#include <assert.h>

Disabling asserts

Asserts can dramatically decrease the performance of a system. There are two main ways of disabling asserts:

  1. Define debug above the include line for assert :

    #define NDEBUG
    #include <assert.h>
    
  2. Compile wth the -DNDEBUG flag:

    $ gcc -DNDEBUG -o <file> <file.c>
    

Uses

Common uses of assert include:

  • Checking for conditions that should never occurr in a correctly running system.

  • Discovering programming errors

  • Assert based testing in COMP1511

  • Checking that memory has been correctly allocated

  • To have the system fail in a more controlled manner (rather than abruptly aborting and consuming resources)

Cases where asserts should not be used include:

  • Handling errors (input or otherwise)

  • Situations in which recovery is required (asserts abort the program)


Example

We can use assert() to check invariants such as whether a pointer is NULL. A common use of assert is to assert that malloc() succeeds (it can fail if the computer runs out of memory). If malloc fails, it will return a NULL pointer, which will cause a segmentation fault when it is dereferenced later in the program. Instead we want to make the program fail in a controlled manner, so we use an ASSERT.

An example of this is given below:

linked_list.c

linked_list.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//Makes a linked list of length 7 and prints it out
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


struct node {
    int data;
    struct node *next;
};

struct node *create_node(int data);
struct node *create_list(int length);
void print_list(struct node *list);

int main(void){
    struct node *list1 = create_list(7);
    print_list(list1);

    return 0;
}

struct node *create_node(int data){
    struct node *new = malloc(sizeof(struct node));
    assert(new != NULL);
    new->data = data;
    new->next = NULL;
    return new;
}

struct node *create_list(int length) {

    struct node *head = NULL;
    if (length > 0) {
        head = create_node(0);
        int i = 1;
        struct node *curr = head;
        while (i < length) {
            curr->next = create_node(i);
            curr = curr->next;
            i++;
        }
    }
    return head;
}

void print_list(struct node *list){
    struct node *curr = list;

    while (curr != NULL) {
        printf("%d->", curr->data);
        curr = curr->next;
    }
    printf("X\n");
}

We can run the program

$ gcc -Wall -Werror -std=c99 -o linked_list linked_list.c
$ ./linked_list
linked_list: linked_list.c:25: create_node: Assertion `new != NULL' failed.
Aborted (core dumped)

In this example, malloc fails and returns a NULL pointer which is picked up by the ASSERT. Alternatively, if there was no assert, the program would crash when the program attempts to set the data field.

Module author: Liz Willer <e.willer@unsw.edu.au>

Date

2020-02-14