#ifdef / #ifndef / #if / #endif
Conditional compilation controls whether specific parts of your source code are compiled based on whether a macro is defined and its value. It is commonly used for cross-platform support, toggling debug code, and preventing header files from being included more than once.
Syntax
// Compiles the block if the macro is defined.
#ifdef MACRO_NAME
code
#endif
// Compiles the block if the macro is NOT defined.
#ifndef MACRO_NAME
code
#endif
// Conditional branching combined with #else.
#ifdef MACRO_NAME
code when the macro is defined
#else
code when the macro is not defined
#endif
// Evaluates a condition based on the macro's value.
#if constant-expression
code
#elif constant-expression
code
#else
code
#endif
// Header guard (idiom to prevent double inclusion).
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
// Header contents
#endif
Conditional Compilation Directives
| Directive | Description |
|---|---|
| #ifdef | Compiles the block if the specified macro is defined. |
| #ifndef | Compiles the block if the specified macro is NOT defined. Used for header guards. |
| #if | Compiles the block if the constant expression is non-zero (true). Allows branching on macro values. |
| #elif | Adds another condition after #if / #ifdef / #ifndef. |
| #else | Defines the block to compile when the preceding condition is false. |
| #endif | Ends the conditional block. |
| defined(MACRO_NAME) | An operator used inside #if to check whether a macro is defined. |
Sample Code
#include <stdio.h>
// Define a macro for debug mode (can also be passed at compile time with -DDEBUG).
#define DEBUG
// Compile-time branching based on the OS.
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM "Windows"
#elif defined(__linux__)
#define PLATFORM "Linux"
#elif defined(__APPLE__)
#define PLATFORM "macOS"
#else
#define PLATFORM "Unknown"
#endif
// Debug log macro (only active when DEBUG is defined).
#ifdef DEBUG
#define LOG(msg) printf("[DEBUG] %s\n", msg)
#else
#define LOG(msg) // Does nothing (removed in release builds).
#endif
int main(void) {
printf("Platform: %s\n", PLATFORM);
LOG("Program started."); // Printed because DEBUG is defined.
int x = 42;
#ifdef DEBUG
// Check the variable value only in debug mode.
printf("[DEBUG] x = %d\n", x);
#endif
// Branch on a constant value using #if.
#define VERSION 2
#if VERSION >= 2
printf("Using features for version 2 or later.\n");
#elif VERSION == 1
printf("Using features for version 1.\n");
#else
printf("Unknown version.\n");
#endif
return 0;
}
Notes
Always add a header guard to every header file. If the same header is included multiple times, it will cause duplicate definition errors for types and functions. Use an all-uppercase, underscore-separated name based on the filename for the header guard macro (e.g., MYHEADER_H) to avoid collisions with other macros.
Some compilers support the non-standard #pragma once directive as a concise alternative to header guards, but since it is not part of the C standard, use the conventional #ifndef pattern when portability is a concern.
For details on #pragma, see #pragma / #error / #warning. For the basics of macro definitions, see #include / #define (constants).
If you find any errors or copyright issues, please contact us.