Preprocessor – the #elif Directive

This (along with the #if directive) is probably the second most complicated preprocessor directive because the controlling expression can be complex and include tricky macro replacements.

#elif is one of five preprocessor selection statements allowing selection of alternative sections of code for compilation. The other four selection statements are: #ifdef, #ifndef, #if, and #else.

Behaviour of this preprocessor directive is the same for both C and C++ compilers.

An identifier is a sequence of letters, numbers and underscore characters. Identifiers must begin with a letter or underscore character.

Purpose

The #elif directive controls whether the statements found between it and a terminating #endif, #else, or #elif directive are compiled or skipped. The decision is based on the value of the controlling expression.

It is used to allow creating more complex code selection blocks, featuring more alternatives.

Format

#if or #ifdef or #ifndef

preprocessor or code statements

#elif controlling_expression

preprocessor or code statements

#endif, #elif, or #else

All preprocessor directives begin with the # symbol. It must be the first character on the line or the first character on the line following optional white space.

Some early compilers flagged an error if # was not the first character on the line.

Spaces or tabs are permitted between the # and elif, but not escape characters or other symbols or macros. The preprocessor removes white space and concatenates the # and elif together.

The following are valid uses:

#elif defined my_macro
# elif defined my_macro;
# elif defined my_macro
# /* comments are white space */ elif defined my_macro

The following are invalid uses:

// #\ is not a valid preprocessor directive
# \t elif defined my_macro
// #" is not a valid preprocessor directive
# "" elif defined my_macro

Rules for the Controlling Expression

The controlling_expression must be made up of: integers, identifiers, macros, character literals, operators, or the preprocessor operator defined. Strings, floating point values, preprocessor directives, the token pasting operator (##), and stringizing operator (#) are invalid and the program is malformed.

The controlling_expression must evaluate to an integer value.

If the controlling expression is non-zero (TRUE), then the statements following the #elif until the end of the block (#endif, #elif, or #else) are compiled.

 #if 0
.
.
.
// because the controlling expression is zero (FALSE) everything
// until the end of the current block (#elif 42) will be skipped
.
.
.
#elif 42
.
.
.
// because everything in the first block was skipped, and this
// controlling expression evaluates to non-zero (TRUE), all the
// statements until the end of the current block (#else) will be
// compiled.
.
.
.
#else
.
.
.
// all the statements here are skipped because the statements in
// the previous block were compiled
.
.
.
#endif

If the controlling expression is zero (FALSE), then the statements following the #elif until the end of the block (#endif, #elif, or #else) are skipped.

Integers can be signed or unsigned and have a minimum range equal to long and unsigned long integers, respectively.

Identifiers that are macro names are expanded and evaluated and their evaluation value replaces the macro name.

If the macro name is evaluated by the defined operator, then it is not expanded:

#define MY_MACRO "twas brillig"
// MY_MACRO will never be expanded or evaluated.
// the defined operator determines if the identifier MY_MACRO
// exists. It returns 1 if the macro is defined or 0 if the macro is
// not defined.
#if 0
// everything in here is skipped
#elif defined MY_MACRO
// code in here will only be compiled if MY_MACRO exists
#endif

Identifiers that are not macro names, are replaced with a value of 0 (zero):

#elif SOME_RANDOM_IDENTIFIER

If the identifier SOME_RANDOM_IDENTIFIER was never defined using #define or was undefined (before its use) using #undef, then it is assigned the value of 0 (zero). To the preprocessor, it looks like:

#elif 0

Character literals are converted into integer values. The value of a character literal appearing in either #if or #elif does not have to be the same as the value a character literal would have in a code expression. This is because the character set used by the preprocessor does not have to be the same as the character set used by the compiler.

Depending on the compiler, character literals may or may not be permitted to have negative values.

Any of the arithmetic, relational, logical, or bitwise operators may be used in the controlling_expression. Evaluation precedence is the same as for the language.

#elif never begins a selection block, it is always used as an alternative selection following a previous #if, #ifdef, #ifndef, or #elif preprocessor directive.