Previous Page
Next Page

14.3. Conditional Compiling

The conditional compiling directives instruct the preprocessor to retain or omit parts of the source code depending on specified conditions. You can use conditional compiling to adapt a program to different target systems, for example, without having to manage a variety of source files.

A conditional section begins with one of the directives #if, #ifdef, or #ifndef, and ends with the directive #endif. Any number of #elif directives, and at most one #else directive, may occur within the conditional section. A conditional section that begins with #if has the following form:

    #if expression1
      [ group1 ]
    [#elif expression2
      [ group2 ]]
    [#elif expression(n)
      [ group(n) ]]
      [ group(n+1) ]]

The preprocessor evaluates the conditional expressions in sequence until it finds one whose value is nonzero, or "true." The preprocessor retains the text in the corresponding group for further processing. If none of the expressions is true, and the conditional section contains an #else directive, then the text in the #else directive's group is retained.

The token groups group1, group2, and so on consist of any C source code, and may include more preprocessing directives, including nested conditional compiling directives. Groups that the preprocessor does not retain for further processing are removed from the program at the end of the preprocessor phase.

14.3.1. The #if and #elif Directives

The expression that forms the condition of an #if or #elif directive must be an integer constant preprocessor expression. This is different from an ordinary integer constant expression (see "Constant Expressions" in Chapter 5) in these respects:

  • You may not use the cast operator in an #if or #elif expression.

  • You may use the preprocessor operator defined (see "The defined Operator," later in this chapter).

  • After the preprocessor has expanded all macros and evaluated all defined expressions, it replaces all other identifiers or keywords in the expression with the character 0.

  • All signed values in the expression have the type intmax_t, and all unsigned values have the type uintmax_t. Character constants are subject to these rules as well. The types intmax_t and uintmax_t are defined in the header file stdint.h.

  • The preprocessor converts characters and escape sequences in character constants and string literals into the corresponding characters in the execution character set. Whether character constants have the same value in a preprocessor expression as in later phases of compiling is up to the given implementation, however.

14.3.2. The defined Operator

The unary operator defined can occur in the condition of an #if or #elif directive. Its form is one of the following:

    defined identifier
    defined (identifier)

These preprocessor expressions yield the value 1 if the specified identifier is a macro namethat is, if it has been defined in a #define directive and its definition hasn't been canceled by an #undef directive. For any other identifier, the defined operator yields the value 0.

The advantage of the defined operation over the #ifdef and #ifndef directives is that you can use its value in a larger preprocessor expression. An example:

    #if defined( _  _unix_  _ ) && defined( _  _GNUC_  _ )
    /* ... */

Most compilers provide predefined macros, like those used in this example, to identify the target system and the compiler. Thus on a Unix system, the macro _ _unix_ _ is usually defined, and the macro _ _GNUC_ _ is defined if the compiler being used is GCC. Similarly, the Microsoft Visual C compiler on Windows automatically defines the macros _WIN32 and _MSC_VER.

14.3.3. The #ifdef and #ifndef Directives

You can also test whether a given macro is defined using the #ifdef and #ifndef directives. Their syntax is:

    #ifdef identifier
    #ifndef identifier

These are equivalent to the following #if directives:

    #if defined identifier
    #if !defined identifier

The conditional code following the #ifndef identifier is retained if identifier is not a macro name. Examples 14-1 and 14-2 illustrate possible uses of these directives.

Previous Page
Next Page