Dr. Roger Ianjamasimanana

How to use the assert.h in C?

By Dr. Roger Ianjamasimanana

1. What is assert.h in C?

The header assert.h declares the assert macro, which checks a given expression at runtime. If the expression evaluates to zero (i.e., it’s false), the program writes an error message to the standard error stream (stderr) and then calls abort() to terminate the process immediately.

The error message typically contains:

  • The failed expression
  • The name of the source file
  • The line number where the assertion failed
  • The function name (in newer C standards or depending on compiler extensions)

2. How does assert work?

When you include assert.h and use assert(condition) in your code, the compiler inserts runtime checks. If condition is false, an error message is printed, and abort() is called, stopping the program. If condition is true, nothing happens and the program proceeds normally.

// Example: Basic usage of assert
#include <stdio.h>
#include <assert.h>

int main(void) {
    int x = 5;
    assert(x == 5);     // passes, nothing happens
    assert(x > 10);     // fails, program will abort with an error message

    printf("This line won't be reached if the second assert fails.\n");
    return 0;
}
Note: If the second assertion fails, you’ll see a message like: Assertion failed: (x > 10), file main.c, line 9, followed by program termination.

3. When to use assert.h?

The primary purpose of assert is to catch programming errors, unexpected states, or logical inconsistencies during development. Common use cases include:

  • Checking preconditions: Ensure that function inputs or global states match your assumptions before performing further operations.
  • Verifying invariants: For data structures or algorithms that maintain certain properties (e.g., a sorted list), assert those properties remain true.
  • Testing assumptions: If you believe some condition must always be true at runtime, an assertion will quickly warn you if it ever becomes false.

Typically, assert is not used for user input validation or production error handling. That’s because assert aborts the program instead of handling the error gracefully. For user-facing scenarios, you’d usually code explicit checks and return error codes or handle them with structured error mechanisms.

4. Enabling and disabling assert.h

In many development workflows, assert statements are enabled for debugging builds but disabled in production or release builds. This behavior is controlled by defining or not defining the NDEBUG macro (No Debug).

If NDEBUG is defined before #include <assert.h>, then all assert calls become no-ops (no operation) — they are effectively removed from the compiled program.

// Example: disabling asserts
#define NDEBUG
#include <assert.h>

int main(void) {
    int y = 0;
    assert(y != 0);  // This does nothing because NDEBUG is defined
    // Program won't abort, even if y == 0
    return 0;
}
Practical tip: you can pass -DNDEBUG to your compiler (e.g. gcc) to define NDEBUG and thus disable asserts in a release build.

5. Things to keep in mind

  • Use for development and testing: assert is extremely helpful during debugging because it immediately flags unexpected conditions.
  • Don’t overuse: if you’re using assert everywhere, you might be testing normal scenarios that should be handled gracefully instead. Reserve it for truly unexpected “should never happen” conditions.
  • Clear conditions: keep your assert expressions simple and direct so that anyone reading the code knows exactly what is being validated.
  • Document the reason: often, it’s useful to add a comment explaining why you expect the condition to always be true, especially for tricky or subtle invariants.
// Good usage example
#include <assert.h>

// We expect 'index' to never be negative at this point.
void process_element(int index) {
    assert(index >= 0);  
    // ...
}
  

6. Common mistakes while using assert.h

  • Relying on asserts in production: if production builds have NDEBUG defined, those checks disappear, so never rely on them for real error handling.
  • Using asserts for expected failures: if a condition can fail under normal circumstances, use a proper error handling approach. Asserts are for conditions that “should never happen.”
  • Side effects in assert: don’t put function calls with side effects inside assert expressions. If NDEBUG is defined, that code won’t even run.

feature-top
Readers’ comment
feature-top
Log in to add a comment
🔐 Access