In C programming language, <assert.h> is a header which is part of the C standard library. It provides assert(), which is used for runtime assertions.
A runtime assertion is when you want to exit the program early because important condition isn't met. For example, you tried to allocate memory with malloc() and got NULL. This is abnormal, so you invoke a runtime assertion to shut down the program.
Note that runtime assertions are for the programmer – not the end user. A user should not be able to cause a runtime assertion by using the program normally. When a user does something wrong, you should generally inform them what they did wrong and exit gracefully, rather than invoke a runtime assertion (also known as “runtime error” or “runtime exception”).
You set runtime assertions like this:
assert(/* I want this to be true */);
For example
// Compile: gcc main.c -o program // Run: ./program #include <assert.h> int main() { assert(1 == 1); assert(0 == 1); printf("This is never printed."); return 0; }
The first assertion does nothing, because 1 == 1 is true.
The second assertion actually kills the program because the asserted condition 0 == 1 is false.
The program prints the following and exits:
program: main.c:7: main: Assertion '0 == 1' failed.
The “This is never printed.” part is, indeed, never printed.
The following are five pieces of information that assert() gives you by default:
Like we've seen in the previous example (using assert(0 == 1)) that looks something like this:
program: main.c:7: main: Assertion '0 == 1' failed.
But what if you wanted to add more information than just '0 == 1' e.g. a string message? Unfortuantely, there is no way to do it other than maybe chain a string literal with a logical “and” operator &&. A string literal – which is a pointer const char* – is always considered “true” because its address is never NULL.
assert(0 == 1 && "need zero to be one");
Which looks like this:
program: main.c:7: main: Assertion '0 == 1 && "need zero to be one"' failed.
But this doesn't look good that good and you're better off implemnting your own assertion API.
Implementation of assert() is the following:
/* Compile: gcc main.c -o give_me_args Run: ./give_me_args arg1 Result: 'Error: No arguments' */ void assert(int condition) { if (! condition) { fprintf(stderr, "Assertion failed."); exit(EXIT_FAILURE); } } int main(int argc, char *argv[]) { assert(argc > 1); }
But the assert() function under <assert.h> is actually not a function but a function macro. Whan an assertion fails it also gives you the C filename, line of code, and what is the condition that failed the assertion.
Commonly, you want to exit the program early in case some condition is not met.
But checking failure with if-statements is a bit tedious and repetitive.
#include <stdlib.h> int main() { FILE *input1 = fopen("input1.txt", "r"); if (input1 == NULL) { fprintf(stderr, "Error: input1 == NULL"); exit(EXIT_FAILURE); } FILE *input2 = fopen("input2.txt", "r"); if (input2 == NULL) { fprintf(stderr, "Error: input2 == NULL"); exit(EXIT_FAILURE); } FILE *input3 = fopen("input3.txt", "r"); if (input3 == NULL) { fprintf(stderr, "Error: input3 == NULL"); exit(EXIT_FAILURE); } fclose(input3); fclose(input2); fclose(input1); return EXIT_SUCCESS; }
Using assert() can make the code somewhat cleaner.
#include <stdlib.h> int main() { FILE *input1 = NULL; FILE *input2 = NULL; FILE *input3 = NULL; assert((input1 = fopen("input1.txt", "r")) != NULL); assert((input2 = fopen("input2.txt", "r")) != NULL); assert((input3 = fopen("input2.txt", "r")) != NULL); fclose(input3); fclose(input2); fclose(input1); return EXIT_SUCCESS; }
However you should remember that you should not use assert if it's something – if you can handle the errors gracefully!
You should rather implement your own error landling (or better yet – use a logging library!) if you
/*
Compile: gcc main.c -o please_provide_arguments
Run: ./please_provide_arguments
Result:
*/
#define fatal_error(fmt, ...) \
do { \
fprintf(fmt, __VA_ARGS__); \
_exit(EXIT_FAILURE) \
} while (0)
int main(int argc, char *argv[])
{
fatal_error("Error: ", 2 + 2);
printf("This is never printed.");
return EXIT_SUCCESS;
}
You can disable the assert() macro by defining the NDEBUG which you can do with -D option:
$ gcc -DNDEBUG main.c -o program
Or, you can do it just before including <assert.h>
#define NDEBUG #include <assert.h>
In both cases, assert() becomes neutered and does nothing:
#define assert(condition) ((void)0)