General topics | ||||||||||||||||
Flow control | ||||||||||||||||
Conditional execution statements | ||||||||||||||||
Iteration statements (loops) | ||||||||||||||||
Jump statements | ||||||||||||||||
Functions | ||||||||||||||||
Function declaration | ||||||||||||||||
Lambda function expression | ||||||||||||||||
inline specifier | ||||||||||||||||
Dynamic exception specifications(until C++17*) | ||||||||||||||||
noexcept specifier(C++11) | ||||||||||||||||
Exceptions | ||||||||||||||||
Namespaces | ||||||||||||||||
Types | ||||||||||||||||
Specifiers | ||||||||||||||||
| ||||||||||||||||
Storage duration specifiers | ||||||||||||||||
Initialization | ||||||||||||||||
Expressions | ||||||||||||||||
Alternative representations | ||||||||||||||||
Literals | ||||||||||||||||
Boolean -Integer -Floating-point | ||||||||||||||||
Character -String -nullptr(C++11) | ||||||||||||||||
User-defined(C++11) | ||||||||||||||||
Utilities | ||||||||||||||||
Attributes(C++11) | ||||||||||||||||
Types | ||||||||||||||||
typedef declaration | ||||||||||||||||
Type alias declaration(C++11) | ||||||||||||||||
Casts | ||||||||||||||||
Memory allocation | ||||||||||||||||
Classes | ||||||||||||||||
Class-specific function properties | ||||||||||||||||
| ||||||||||||||||
Special member functions | ||||||||||||||||
Templates | ||||||||||||||||
Miscellaneous | ||||||||||||||||
#if#ifdef#ifndef#else#elif#elifdef#elifndef#endif (C++23)(C++23) | ||||
(C++17) | ||||
(C++23) | ||||
(C++11) | ||||
(C++26) |
The preprocessor supports conditional compilation of parts of source file. This behavior is controlled by#if
,#else
,#elif
,#ifdef
,#ifndef
,#elifdef
,#elifndef
(since C++23), and#endif
directives.
Contents |
#if expression | |||||||||
#ifdef identifier | |||||||||
#ifndef identifier | |||||||||
#elif expression | |||||||||
#elifdef identifier | (since C++23) | ||||||||
#elifndef identifier | (since C++23) | ||||||||
#else | |||||||||
#endif | |||||||||
The conditional preprocessing block starts with#if
,#ifdef
or#ifndef
directive, then optionally includes any number of#elif
,#elifdef
, or#elifndef
(since C++23) 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
,#ifdef
,#ifndef
,#elif
,#elifdef
,#elifndef
(since C++23), and#else
directives control the code block until the first#elif
,#elifdef
,#elifndef
(since C++23),#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
,#elifdef
,#elifndef
,(since C++23) and#elif
directives are ignored. Otherwise, if the specified condition evaluates false, the controlled code block is skipped and the subsequent#else
,#elifdef
,#elifndef
,(since C++23) or#elif
directive (if any) is processed. If the subsequent directive is#else
, the code block controlled by the#else
directive is unconditionally compiled. Otherwise, the#elif
,#elifdef
, or#elifndef
(since C++23) 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
,#elifdef
,#elifndef
,(since C++23) and#else
directives. The conditional preprocessing block is terminated by#endif
directive.
expression may contain unary operators in formdefined
identifier ordefined (
identifier)
. The result is1 if theidentifier wasdefined as a macro name, otherwise the result is0.
expression may also contain the following expressions:
The identifiers mentioned above are treated as if they were the names of defined macros in this context. | (since C++17) |
After all macro expansion and evaluationdefined
and the expressions described above, any identifier which is not aboolean literal is replaced with the number0 (this includes identifiers that are lexically keywords, but not alternative tokens likeand).
Then the expression is evaluated as anintegral constant expression.
If theexpression evaluates to nonzero value, the controlled code block is included and skipped otherwise.
Note: Until the resolution ofCWG issue 1955,#ifcond1
...#elifcond2
is different from#ifcond1
...#else
followed by#ifcond2
because ifcond1
is true, the second#if
is skipped andcond2
does not need to be well-formed, while#elif
'scond2
must be a valid expression. As of CWG 1955,#elif
that leads the skipped code block is also skipped.
Checks if the identifier wasdefined as a macro name.
#ifdef
identifier is essentially equivalent to#if defined
identifier.
#ifndef
identifier is essentially equivalent to#if !defined
identifier.
| (since C++23) |
While#elifdef
and#elifndef
directives target C++23, implementations are encouraged to backport them to the older language modes as conforming extensions.
#define ABCD 2#include <iostream> int main(){ #ifdef ABCDstd::cout<<"1: yes\n";#elsestd::cout<<"1: no\n";#endif #ifndef ABCDstd::cout<<"2: no1\n";#elif ABCD == 2std::cout<<"2: yes\n";#elsestd::cout<<"2: no2\n";#endif #if !defined(DCBA) && (ABCD < 2*4-3)std::cout<<"3: yes\n";#endif // Note that if a compiler does not support C++23's #elifdef/#elifndef// directives then the "unexpected" block (see below) will be selected.#ifdef CPUstd::cout<<"4: no1\n";#elifdef GPUstd::cout<<"4: no2\n";#elifndef RAMstd::cout<<"4: yes\n";// expected block#elsestd::cout<<"4: no!\n";// unexpectedly selects this block by skipping// unknown directives and "jumping" directly// from "#ifdef CPU" to this "#else" block#endif // To fix the problem above we may conditionally define the// macro ELIFDEF_SUPPORTED only if the C++23 directives// #elifdef/#elifndef are supported.#if 0#elifndef UNDEFINED_MACRO#define ELIFDEF_SUPPORTED#else#endif #ifdef ELIFDEF_SUPPORTED#ifdef CPUstd::cout<<"4: no1\n";#elifdef GPUstd::cout<<"4: no2\n";#elifndef RAMstd::cout<<"4: yes\n";// expected block#elsestd::cout<<"4: no3\n";#endif#else // when #elifdef unsupported use old verbose “#elif defined”#ifdef CPUstd::cout<<"4: no1\n";#elif defined GPUstd::cout<<"4: no2\n";#elif !defined RAMstd::cout<<"4: yes\n";// expected block#elsestd::cout<<"4: no3\n";#endif#endif}
Possible output:
1: yes2: yes3: yes4: no!4: yes
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++98 | failed#elif's expression was required to be valid | failed#elif is skipped |
C documentation forConditional inclusion |