C preprocessor" -- Overview" "

Preprocessing encompasses all tasks that logically precede the translation of a program. The preprocessor processes headers, expands macros, and conditionally includes or excludes source code.

Directives

The C preprocessor recognizes the following directives:

##iiff              Include code if a condition is true
##eelliiff            Include code if directive is true
##eellssee            Include code if preceding directives fail
##eennddiiff           End of code to be included conditionally

##iiffddeeff           Include code if a given macro is defined
##iiffnnddeeff          Include code if a given macro is not defined

##ddeeffiinnee          Define a macro
##uunnddeeff           Undefine a macro
##iinncclluuddee         Read another file and include it
##lliinnee            Reset current line number

The COHERENT preprocessor also recognizes the directive #pragma, which performs implementation- specific tasks. See the Lexicon entry on #pragma for details.

A preprocessing directive is always introduced by the `#' character. The `#' must be the first non-white space character on a line, but it may be preceded by white space and it may be separated from the directive name that follows it by one or more white space characters.

Preprocessing Operators

The Standard defines two operators that are recognized by the preprocessor: the ``stringize'' operator #, and the ``token-paste'' operator ##. It also defines a new keyword associated with preprocessor statements: defined.

The operator # indicates that the following argument is to be replaced by a string literal; this literal names the preprocessing token that replaces the argument. For example, consider the macro:

     #define display(x) show((long)(x), #x)

When the preprocessor reads the line

     display(abs(-5));

it replaces it with the following:

     show((long)(abs(-5)), "abs(-5)");

The ## operator performs ``token pasting'' -- that is, it joins two tokens together, to create a single token. For example, consider the macro:

     #define printvar(x) printf("%d\n", variable ## x)

When the preprocessor reads the line

     printvar(3);

it translates it into:

     printf("%d\n", variable3);

In the past, token pasting had been performed by inserting a comment between the tokens to be pasted. This no longer works.

Predefined Macros

The ANSI Standard describes the following macros that must be recognized by the preprocessor:
    ____DDAATTEE____ Date of translation
    ____FFIILLEE____ Source-file name
    ____LLIINNEE____ Current line within source file
    ____SSTTDDCC____ Conforming translator and level
    ____TTIIMMEE____ Time of translation

For more information on any one of these macros, see its entry.

Conditional Inclusion

The preprocessor will conditionally include lines of code within a program. The directives that include code conditionally are defined in such a way that you can construct a chain of inclusion directives to include exactly the material you want.

The preprocessor keyword defined determines whether a symbol is defined to the #if preprocessor directive. For example,

     #if defined(SYMBOL)

or

     #if defined SYMBOL

is equivalent to

     #ifdef SYMBOL

except that it can be used in more complex expressions, such as

     #if defined FOO && defined BAR && FOO==10

defined is recognized only in lines beginning with #if or #elif.

Note that defined is a preprocessor keyword, not a preprocessor directive or a C keyword. You could, for example, write a function called defined() without any complaint from the C compiler.

The COHERENT preprocessor implicitly defines the following macros:

     __COHERENT__
     __MWC__
     __IEEE__
     __I386__

     _IEEE
     _I386
     MWC
     COHERENT

These can be used to include conditionally code that applies to a specific edition of COHERENT. COHERENT 286 uses DECVAX floating-point code; whereas COHERENT 386 uses IEEE. If you were writing code that intensively used floating-point numbers and you wanted to compile the code under both editions of COHERENT, you could write code of the form:

     #ifdef _DECVAX
          ...
     #elif _IEEE
          ...
     #endif

The C preprocessor under each edition of COHERENT would ensure that the correct code was included for compilation.

Macro Definition and Replacement

The preprocessor performs simple types of macro replacement. To define a macro, use the preprocessor directive ##ddeeffiinnee _i_d_e_n_t_i_f_i_e_r _v_a_l_u_e. The preprocessor scans the translation unit for preprocessor tokens that match identifier; when one is found, the preprocessor substitutes value for it.

Inclusion of Macros or Functions

The ANSI standard demands that every routine implemented as a macro also be implemented as a function, with the exception of the macro va_arg(). For example, COHERENT implements the STDIO routines toupper() and tolower() both as macros and functions.

By default, COHERENT uses the macro version of routines. To force it to use the function of a routine, you must undefine the macro version. You can do that either by using the preprocessor instruction #undef in your code, or by using the option -U on the cc command line. For example, to compel COHERENT to use the function version of tolower(), include the statement

     #undef tolower

in your program, or include the argument

     -Utolower

on the cc command line.

cpp

Under COHERENT, C preprocessing is done by the program cpp. The cc command runs cpp as the first step in compiling a C program. cpp can also be run by itself.

cpp reads each input file; it processes directives, and writes its product on ssttddoouutt.

If its -E option is not used, cpp also writes into its output statements of the form ##lliinnee _n _f_i_l_e_n_a_m_e, so that the parser cc0 can connect its error messages and debugger output with the original line numbers in your source files.

See the Lexicon entry on cpp for more information.

See Also