#if directive — Tests a condition
#if constant-expression
The #if
directive begins a
region of conditional compilation, that is, a region within a source
file where preprocessor directives determine whether the code in the
region is compiled. A conditional region starts with #ifdef
, #ifndef
, or #if
and ends with #endif
. Each region can have any number of
#elif
directives and an optional
#else
directive after all the
#elif
directives. The basic form to
use is:
#if defined(_ _win32_ _) const char os[] = "Microsoft Windows"; #elif defined(__linux__) or defined(_ _unix_ _) const char os[] = "UNIX (or variant)"; #elif defined(_ _vms_ _) const char os[] = "VMS"; #else const char os[] = "(unknown)"; #endif
Macros in the directive argument are expanded, except for the
operands of the defined
operator.
The constant expression is evaluated, and if the result is nonzero,
the #if
condition is true, and the
code in the region that immediately follows is compiled. The region
ends with #else
, #elif
, or #endif
. If the #if
expression is false, the condition for
the next #elif
is evaluated, and if
that expression is true, its region is compiled, and so on. If all
#elif
expressions are false, and
#else
is present, its region is
compiled. Conditional processing ends with the corresponding #endif
directive.
Conditionals can be nested. Within an inner region, the preprocessor keeps track of conditional directives even if the region is not being compiled, so conditional directives can be properly matched.
The #if
and #elif
directives take a single parameter, a
constant expression. The expression differs slightly from
non-preprocessor constant expressions:
You can use the defined
operator.
Integers are long
, that
is, int
values (and values that
are promoted to int
) have the
same representation as long
int
, and unsigned
int
values have the same representation
as unsigned
long
. All bool
values are promoted to integers,
including the keywords true
and
false
.
Character literals are converted to the execution character set. The numeric value of a character in a preprocessor expression is not necessarily the same as the value of the same character in a non-preprocessor expression. A character may have a negative value.
Keywords that are alternative operators for symbolic
operators (i.e., and
, and_eq
, bitand
, bitor
, compl
, not
, not_eq
, or
, or_eq
, xor
, and xor_eq
) have their usual meaning,
although it is ineffective to try using assignment operators
(and_eq
, or_eq
, and xor_eq
) in an #if
or #elif
condition.
Other identifiers and keywords that remain after macro
expansion are replaced by 0
.
(It might seem strange to convert keywords, such as sizeof
, to the integer 0
, but that is the rule. Some compilers
fail to follow this particular rule.) One consequence of this rule
is that you cannot use type casts or new
, delete
, sizeof
, throw
, or typeid
expressions in an #if
or #elif
condition.
Conditional directives are most often used to guard header files
from multiple inclusion. All the standard headers are guarded, so
including them more than once has no harmful effects. This is
important because an implementation might include one header in
another header. For example, <map>
might include <utility>
to get the declaration for
the pair<>
template. If you
explicitly #include
<map>
and #include
<utility>
, you might end up including
<utility>
more than
once.
Another common use is for system- or compiler-specific code.
Every compiler predefines one or more macros to identify the compiler
and possibly the host operating system (such as _ _linux_ _
or _
_GNUC_ _
). Consult your compiler's documentation to learn
which macro names are predefined.
Example 11-4 shows one way to nest conditional directives.
Example 11-4. Nesting conditional directives
#define zero zero // Identifiers are converted to 0. #define one true // Bool expressions are promoted to int.#if one
// This region is compiled.#if zero
This region can contain erroneous C++ code. The code is not compiled, so the errors do not matter.#else
// This #else matches the inner #if. // This region is compiled. const int zero = 0;#endif
// This #endif matches the inner #if. int x = zero;#else
This #else matches the outer #if. Because the #if condition was true, the #else region is not compiled.#endif
You can guard your own headers by using conditional directives to define a guard macro and using the guard macro to ensure the file's contents are compiled only when the macro is not defined, as shown in Example 11-5.
Example 11-5. Guarding a header against multiple inclusion
// In the header file employee.h#ifndef EMPLOYEE_H
#define EMPLOYEE_H
// Thus, the entire contents of the file are compiled only when EMPLOYEE_H is not // defined. The first time the file is #included, the macro is not defined, in // which case it is immediately defined. The second and subsequent times the same // header is included in the same source file; the macro and conditional // directives ensure that the entire file is skipped. class employee { ... };#endif
// End of employee.h