How to Disable Assert in C Release Builds
In C programming, runtime assertions using the standard
assert() macro are critical for catching logic bugs during
development, but they introduce unwanted performance overhead and
potential binary size increases in production. This article explains how
to completely disable runtime assertion checking in C release builds
using the standard NDEBUG preprocessor macro, how to apply
it across major build systems, and important pitfalls to avoid when
disabling assertions.
The Standard Mechanism:
The NDEBUG Macro
The standard C library handles assertion control via the
NDEBUG (No Debug) macro. According to the ISO C standard,
if NDEBUG is defined at the point where
<assert.h> is included, the assert()
macro is defined as:
#define assert(ignore) ((void)0)This transforms every assert() call into an empty
statement, causing the compiler to emit no machine code for the
assertion checks. Consequently, condition evaluation, string literals
for error messages, and abort calls are entirely omitted from the
compiled binary.
Method 1: Disabling via Compiler Flags (Recommended)
The standard and most maintainable approach is to define
NDEBUG globally in your build system for release
configurations. This ensures every source file compiles with assertions
disabled without modifying the source code.
GCC and Clang
Pass the -D flag followed by NDEBUG:
gcc -O3 -DNDEBUG main.c -o my_programMSVC (Microsoft Visual C++)
Pass the /D flag:
cl /O2 /DNDEBUG main.cCMake
In a modern CMake configuration, NDEBUG is typically
added automatically for Release and
RelWithDebInfo build types. If setting flags manually,
use:
target_compile_definitions(my_target PRIVATE $<$<CONFIG:Release>:NDEBUG>)Method 2: Disabling via Source Code
You can disable assertions directly inside a C source file by
defining NDEBUG before including
<assert.h>:
#define NDEBUG
#include <assert.h>
void process_data(int *ptr) {
assert(ptr != NULL); // This check will be completely ignored by the compiler
// ...
}Note: If #include <assert.h> appears before
#define NDEBUG, assertions will remain active for that
compilation unit unless NDEBUG is defined at the compiler
level.
Critical Warning: Side Effects in Assertions
When assertions are disabled, the expression inside
assert() is never evaluated. A common bug occurs when
expressions with side effects are placed inside an assertion:
// BUG: perform_setup() will not execute in a release build
assert(perform_setup() == 1);To prevent this issue, separate the operation from the verification:
int status = perform_setup();
assert(status == 1);
(void)status; // Suppress unused-variable warnings in release builds