In this article, we’ll take a look at using the concept of assertions, using the assert in C/C++.
This is not very hard to understand, so let’s get started!
We’ll first look at what we mean by an assertion, and then look at how we can use it in our C programs to debug effectively!
What is an assertion?
An assertion is a specification that verifies that a program satisfies certain conditions at particular points, during its execution (run-time condition checks).
For computer programs, there are primarily three types of assertions checks:
- Precondition Assertion -> Condition satisfied before main body execution
- Post-condition Assertion -> Condition satisfied after main body execution
- Invariant Assertion -> Condition satisfied after every repetitive region of a function (like a loop)
Now that we know what an assertion is, let’s look at doing this in a C program.
Using assertions in C programs
In C, we use the assert macro to define an assertion statement. This is there in the <assert.h>
header file.
To define an assertion, we can write something like this:
1 2 |
#include <assert.h> assert (condition); |
Here, condition
must be boolean. For example, the below is an example of an assertion:
1 2 |
int i=0; assert (i >= 0); |
The above assertion holds true, since 0>=0
. Therefore, during execution, our program continues normally.
If the assert condition holds false, it will produce an error, and our program will stop executing, with suitable error messages.
1 2 3 |
int i = 0; // This is false assert (i > 0); |
Now that we’ve covered the basics, let’s look at using assertions in a for loop.
This not only ensures that we want the program to do what we want, but also structures code logically, so that it is easy to read.
An example – Using assert in a loop
Consider the below code, that simply adds integers within a given range. We want to ensure that our final result is always positive, and does not overflow.
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 |
#include <stdio.h> #include <limits.h> #include <assert.h> int loop_function(int a, int b) { // Precondition assertion (a <= b) assert (a <= b); int result = 0; for (int i=a; i<=b; i++) { // Invariant assertion // The cummulative result must always be positive // Sometimes, the result may overflow and give a negative // integer. In that case, this assertion will fail assert (result >= 0); result += i; } // Postcondition assertion // Again, the net result must be positive // So if result = 0, this condition will fail assert (result > 0); return result; } int main() { int a = 3; int b = 10; printf("loop_function on %d and %d gives %dn", a, b, loop_function(a, b)); int c = INT_MAX - 3; int d = INT_MAX; // Here, in case of c and d, the result will overflow. The invariant assertion will be false! printf("loop_function on %d and %d gives %dn", c, d, loop_function(c, d)); return 0; } |
Output
1 2 3 |
loop_function on 3 and 10 gives 52 assert_loop: assert_loop.c:14: loop_function: Assertion `result >= 0' failed. [1] 337 abort (core dumped) ./assert_loop |
If the value of our result is too high (beyond the integer size), then the result will overflow and become negative!
Our second set of input does this, and hence the loop invariant assertion will fail!
So our program will halt there itself. This ensures that we can detect any design flaw in our program, and handle such inputs accordingly.
Conclusion
In this article, we learned how we could check for assertions, using the assert macro in C/C++. For similar articles on C, do look at our tutorial section on C programming.