The <assert.h> header provides the assert macro—a simple debugging tool that verifies assumptions in your code. When a check fails, you get a clear error message and the program stops immediately so you can fix the bug early.
01
assert
Debug macro.
02
assert.h
One header.
03
NDEBUG
Disable in release.
04
abort()
On failure.
05
Invariants
Internal checks.
06
Not users
Dev-only tool.
Fundamentals
Definition and Usage
assert(expression) tests whether expression is non-zero (true). If it evaluates to zero (false), the implementation prints a diagnostic to stderr (typically including the expression, file name, and line number) and calls abort() to terminate the program.
Use assert to document assumptions that must hold if your code is correct—non-null pointers after allocation, valid array indices, preconditions on function arguments. It is a development aid, not a substitute for handling recoverable errors from users or the OS.
💡
Beginner Tip
assert is a macro, not a function. Never put side effects inside assert (like assert(i++))—when you compile with -DNDEBUG, that code may disappear entirely.
Foundation
📝 Syntax
Include the header and use the macro:
C
#include <assert.h>
assert(expression);
Macro defined in assert.h
assert(expression) — if expression is false (zero), print diagnostic and call abort(). If true (non-zero), no effect.
Disabling assertions
C
#define NDEBUG /* define before #include <assert.h> */
#include <assert.h>
/* Or compile: gcc -DNDEBUG ... */
Parameters
expression — any scalar expression with a value comparable to zero. Common forms: ptr != NULL, n >= 0, index < size.
Headers and linking
#include <assert.h>
No special link flag required (unlike math.h).
Compile: gcc program.c -std=c11 -o program
Cheat Sheet
⚡ Quick Reference
Pattern
Meaning
On failure
assert(ptr != NULL)
Pointer must be valid
abort + message
assert(n >= 0)
Non-negative count
abort + message
assert(i < len)
Index in bounds
abort + message
#define NDEBUG
Strip all asserts
no-op
static_assert(...)
Compile-time check (C11)
build error
Include
#include <assert.h>
Standard header
Check
assert(condition)
Runtime macro
Release
-DNDEBUG
Remove asserts
Not for
user errors
Use return codes
Hands-On
Examples Gallery
Compile debug examples without NDEBUG to see assertions fire. Use gcc file.c -std=c11 -g -o out for clear line numbers in failure messages.
📚 Getting Started
Catch invalid arguments before they cause silent bugs.
Example 1 — Assert Non-Negative Input for sqrt()
Classic pattern from the reference: guard a function precondition.
The first call succeeds. The second passes a negative value; assert fails, prints the expression and location, and aborts before sqrt receives invalid input. Link with -lm if needed.
Example 2 — Assert Pointer Is Not NULL
Document that a pointer argument must be valid before dereferencing.
C
#include <assert.h>
#include <stdio.h>
void print_length(const char *text) {
assert(text != NULL);
printf("Length check: first char is '%c'\n", text[0]);
}
int main(void) {
print_length("hello");
print_length(NULL);
return 0;
}
📤 Output:
Length check: first char is 'h'
a.out: assert_ptr.c:5: print_length: Assertion `text != NULL' failed.
How It Works
Without assert, dereferencing NULL causes undefined behavior. The assertion fails fast with a readable message during development.
📈 Practical Patterns
Bounds checks, release builds, and proper error handling.
Example 3 — Array Index Bounds Check
Verify an index is inside the array before access.
Invalid user input returns -1 without crashing. assert documents that if execution reaches past the if, n must be positive—a guarantee for maintainers and debug builds.
Applications
🚀 Common Use Cases
Function preconditions — arguments must satisfy contracts (non-null, in range).
Postconditions — result of a function meets expectations before return.
Loop invariants — index stays within bounds each iteration during development.
Unreachable code — assert(0 && "should not reach here") after a full switch.
Unit testing aid — catch logic errors early while writing tests.
Documentation — assertions spell out assumptions readers might miss.
🧠 How assert() Works
1
Evaluate expression
The macro evaluates expression once (when not disabled).
Check
2
Non-zero?
If true, execution continues with no effect.
Pass
3
Print diagnostic
On failure: message to stderr with expression, file, line.
Fail
=
🛑
abort()
Program terminates immediately. Use a debugger to inspect the failure site.
Important
📝 Notes
assert is a macro, not a function—no guaranteed stack frame or single evaluation when NDEBUG is set.
Define NDEBUG before #include <assert.h> to disable all assertions.
Failed assert calls abort()—not recoverable; unsuitable for user input errors.
Do not put side effects inside assert(expression).
static_assert (C11) is separate—compile-time only, keyword not in assert.h.
Assertion messages and exact format vary slightly by compiler (GCC, Clang, MSVC).
Performance
⚡ Optimization
In debug builds, assert adds a branch and possibly string data at each site. That is acceptable during development. For release builds, compile with -DNDEBUG (or -O2 projects that define it) so assertions compile out entirely—zero runtime cost.
Avoid dense assert calls in inner loops on hot paths even in debug builds; prefer checking invariants at function entry or less frequently.
Wrap Up
Conclusion
<assert.h> gives you a lightweight way to catch logic errors during development. The assert macro documents assumptions, fails loudly with file and line information, and strips cleanly from release builds via NDEBUG.
Use it for internal invariants, not user-facing validation. Pair debug assertions with proper error returns for production robustness.
Use assert for programmer errors and impossible states
Strip asserts in release with -DNDEBUG
Write clear expressions: assert(ptr != NULL)
Combine with return codes for user-facing validation
Run debug builds with assertions during testing
❌ Don’t
Put side effects inside assert(...)
Assert on untrusted user or network input
Rely on assert for security checks in production
Assume assert is a function you can rely on at runtime in release
Confuse assert with static_assert
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about assert.h
Debug assertions in C, explained simply.
5
Core concepts
🔎01
Macro
Not function.
Basics
🛑02
abort()
On failure.
Behavior
📈03
NDEBUG
Strip asserts.
Release
📄04
Invariants
Dev checks.
Purpose
🔄05
Return codes
User errors.
Production
❓ Frequently Asked Questions
assert.h is a standard header that defines the assert macro. assert(expression) checks that expression is true during development. If it is false (zero), the program prints a diagnostic message to stderr and calls abort() to terminate.
assert is a macro, not a function. The standard shows it as assert(expression) but it expands to code that may include __FILE__ and __LINE__. Do not rely on assert having function-call semantics (e.g. side effects may be skipped when NDEBUG is defined).
Define NDEBUG before including assert.h, or compile with -DNDEBUG. When NDEBUG is defined, assert(expression) expands to nothing and is removed from the binary. This is the standard way to strip assertions from production builds.
No. assert is for programmer mistakes and internal invariants during development. User-facing errors (bad files, invalid forms) need proper error handling—return codes, errno, or error messages—not abort(). Users should never crash your app because of assert.
The implementation writes a message like 'Assertion `expr' failed' with file and line to stderr, then calls abort(). The program terminates immediately. There is no recovery—design assert for impossible states you want to catch while debugging.
assert checks a runtime expression. static_assert (C11) checks a compile-time condition and fails the build if false. Use static_assert for type sizes and constants known at compile time; use assert for runtime assumptions.
Did you know?
The name NDEBUG means “no debug”—defining it tells the implementation to omit assertion checks. Many release build scripts pass -DNDEBUG automatically alongside optimizations, so never put essential logic inside an assert expression.