The #if, #elif, #else, and #endif Directives

The #if directive, together with the #elif, #else, and #endif directives, controls compilation of portions of a source file. If the expression you write (after the #if) has a nonzero value, the statements immediately following the #if directive are retained in the translation unit.

Syntax

preprocessing-file :
group opt

group :
group-part
group group-part


group-part :
pp-tokens opt new-line
if-section
control-line


if-section :
if-group elif-groups opt else-group opt endif-line

if-group :
#if restricted-constant-expression new-line group opt
#ifdef identifier new-line group opt
#ifndef identifier new-line group opt

elif-groups :
elif-group
elif-groups elif-group


elif-group :
#elif restricted-constant-expression new-line group opt

else-group :
#else new-line group opt

endif-line :
#endif new-line

control-line :
#include "path-spec" new-line /* Programmer-supplied header files */
#include <path-spec> new-line /* Standard C header files */
#define identifier replacement-list new-line /* Macro with arguments */
#define identifier (identifier-listopt new-line) replacement-list
#undef identifier new-line
#line digit-sequence new-line
#line digit-sequence "filename" opt new-line
#line digit-sequence preprocessing-tokens new-line
#error preprocessor-tokens opt new-line
#pragma pragma-directive opt new-line
# new-line

replacement-list :
pp-tokens opt
pp-tokens :
preprocessing-token
pp-tokens preprocessing-token

preprocessing-token :
header-name
identifier
pp-number
character-constant
string-literal
operator
punctuator
each nonwhite-space character that cannot be one of the above

new-line : the newline character

Each #if directive in a source file must be matched by a closing #endif directive. Any number of #elif directives can appear between the #if and #endif directives, but at most one #else directive is allowed. The #else directive, if present, must be the last directive before #endif.

The #if, #elif, #else, and #endif directives can nest in the text portions of other #if directives. Each nested #else, #elif, or #endif directive belongs to the closest unmatched #if directive.

The preprocessor selects a single group by evaluating the restricted constant expression following each #if or #elif directive until it finds a true (nonzero) restricted constant expression. It selects all text (including other preprocessor directives beginning with #) up to its associated #elif, #else, or #endif.

The constant expressions used with the #if directives are called restricted-constant-expressions since some restrictions apply here that do not apply to all constant expressions. The preprocessor processes the selected group and passes it to the compiler. If group contains preprocessor directives, the preprocessor carries out those directives. Any text blocks not selected by the preprocessor are not compiled.

If all occurrences of restricted-constant-expression are false, or if no #elif directives appear, the preprocessor selects the text block after the #else clause. If the #else clause is omitted, and all instances of restricted-constant-expression in the #if block are false, no text block is selected.

The Restricted Constant Expression

The restricted-constant-expression is an integer constant expression with these additional restrictions:

All expressions must have integral type and can only include integer constants and character constants.

The expression cannot use sizeof or a type cast operator, nor can assignment operators and the sequential evaluation operator (,) be used in the constant expression.

The translation represents type int the same as type long and unsigned int the same as unsigned long.

The compiler can translate character constants to a set of code values different from the set for the target environment. To determine the properties of the target environment, check values of macros from LIMITS.H in an application built for the target environment. The target environment may not be able to represent all ranges of integers.

The expression must not perform any environmental inquiries and must remain insulated from implementation details on the target computer.

The defined Operator

The restricted-constant-expression can contain the preprocessor operator defined as shown:

defined(identifier) defined identifier /* Alternative equivalent form */

This constant expression is considered true (nonzero) if the identifier is currently defined as a macro; otherwise, the condition is false (0). An identifier defined as empty text is considered defined. The defined directive can be used in a #if and a #elif, but nowhere else.

In the following example, the #if and #endif directives control compilation of one of three function calls.

#if defined(CREDIT)

credit();

#elif defined(DEBIT)

debit();

#else

printerror();

#endif

The function call to credit is compiled if the macro CREDIT is defined. If the identifier DEBIT is defined, the function call to debit is compiled. If neither identifier is defined, the call to printerror is compiled. Note that CREDIT and credit are distinct identifiers in C because their cases are different.

The following conditional compilation statements assume a constant named DLEVEL has already been defined. If an identifier used with #if has not been defined, the identifier evalutes to 0.

#if DLEVEL > 5 /* First example */

#define SIGNAL 1

#if STACKUSE == 1

#define STACK 200

#else

#define STACK 100

#endif

#else

#define SIGNAL 0

#if STACKUSE == 1

#define STACK 100

#else

#define STACK 50

#endif

#endif

#if DLEVEL == 0 /* Second example */

#define STACK 0

#elif DLEVEL == 1

#define STACK 100

#elif DLEVEL > 5

display( debugptr );

#else

#define STACK 200

#endif

The #if block in the first example shows two sets of nested #if, #else, and #endif directives. The first set of directives is processed only if DLEVEL > 5 is true. Otherwise, the statements after the #else are processed.

The #elif and #else directives in the second example are used to make one of four choices, based on the value of DLEVEL. The constant STACK is set to 0, 100, or 200, depending on the definition of DLEVEL. If DLEVEL is greater than 5, then the statement

#elif DLEVEL > 5

display(debugptr);

is compiled and STACK is not defined.

Microsoft Specific

The identifiercan be passed from the command line using the /D option. Up to 30 macros can be specified with /D.This is useful for checking if a definition exists since a definition can be passed from the command line. For example,

#if !defined test /* These three statements go in your source code */

#define final

#endif

CL /Dtest /* This is the command for compilation */

In this example, a macro named final is defined if test has not been defined. You can enter either test or final from the command line at compilation time. The example above shows test being entered from the command line. Alternatively, you can use PWB. From the PWB Options menu, choose Language Options. Then select Additional Global Options or Additional Debug Options and type the constants for your program.

Conditional compilation expressions are treated as signed long values. For example, this expression is true:

#if 0xFFFFFFFFL > 1UL

These expressions are evaluated using the same rules as expressions in C.¨