Conditional inclusion
The preprocessor supports conditional compilation of parts of source file. This behavior is controlled by #if
, #else
, #elif
, #ifdef
, #ifndef
and #endif
directives.
Syntax
#if expression
|
|||||||||
#ifdef identifier
|
|||||||||
#ifndef identifier
|
|||||||||
#elif expression
|
|||||||||
#else
|
|||||||||
#endif
|
|||||||||
Explanation
The conditional preprocessing block starts with #if
, #ifdef
or #ifndef
directive, then optionally includes any number of #elif
directives, then optionally includes at most one #else
directive and is terminated with #endif
directive. Any inner conditional preprocessing blocks are processed separately.
Each of #if
, #elif
, #else
, #ifdef
and #ifndef
directives control code block until first #elif
, #else
, #endif
directive not belonging to any inner conditional preprocessing blocks.
#if
, #ifdef
and #ifndef
directives test the specified condition (see below) and if it evaluates to true, compiles the controlled code block. In that case subsequent #else
and #elif
directives are ignored. Otherwise, if the specified condition evaluates false, the controlled code block is skipped and the subsequent #else
or #elif
directive (if any) is processed. In the former case, the code block controlled by the #else
directive is unconditionally compiled. In the latter case, the #elif
directive acts as if it was #if
directive: checks for condition, compiles or skips the controlled code block based on the result, and in the latter case processes subsequent #elif
and #else
directives. The conditional preprocessing block is terminated by #endif
directive.
Condition evaluation
#if, #elif
The expression is a constant expression.
The expression may contain unary operators in form defined
identifier or defined (
identifier)
. The result is 1 if the identifier was defined as a macro name or the identifier is __has_include (since C++17), otherwise the result is 0.
After all macro expansion and evaluation of defined
and __has_include
(since C++17) expressions, any identifier which is not a boolean literal is replaced with the number 0 (this includes identifiers that are lexically keywords, but not alternative tokens like and
).
If the expression evaluates to nonzero value, the controlled code block is included and skipped otherwise.
Note: |
(until C++14) |
#ifdef, #ifndef
Checks if the identifier was defined as a macro name.
#ifdef
identifier is essentially equivalent to #if defined
identifier.
#ifndef
identifier is essentially equivalent to #if!defined
identifier.
Example
#define ABCD 2 #include <iostream> int main() { #ifdef ABCD std::cout << "1: yes\n"; #else std::cout << "1: no\n"; #endif #ifndef ABCD std::cout << "2: no1\n"; #elif ABCD == 2 std::cout << "2: yes\n"; #else std::cout << "2: no2\n"; #endif #if!defined(DCBA) && (ABCD < 2*4-3) std::cout << "3: yes\n"; #endif }
Output:
1: yes 2: yes 3: yes
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 1955 | C++14 | failed #elif's expression was required to be valid | failed elif is skipped |