C preprocessor

The C preprocessor ( cpp, also C precompiler ) is the preprocessor of the C language in many implementations it is a stand-alone computer program that is invoked by the compiler as the first step of the translation. The preprocessor instructions edited to insert code ( # include), to replace macros ( # define ), and conditional translation (# if). The language of preprocessor directives is not specific to the grammar of the language C. Therefore, the C preprocessor can also be used to process other types of files.

Background

The C programming language possessed in their earliest versions do not have a preprocessor. He was, among other things, at the instigation of Alan Snyder (see also: Portable C Compiler) introduced, but mainly to allow in C inclusion of other source files as in BCPL ( a predecessor language of C ) and allow replacing simple parameterless macros. Advanced by Mike Lesk and John Reiser prone to parameter macros, and constructs for conditional compilation, it developed over time from the optional program of a compiler for a standardized component of the programming language. The independent development of the core language explains the discrepancies in the language syntax between C and its preprocessor.

In the early years of the preprocessor was a separate program that handed its interim result to the actual compiler that translated it then. Today, the preprocessor statements are taken into account by the compilers for C and C in a single operation. On request of them additionally or exclusively the result will be issued, which would have delivered a preprocessor.

The C preprocessor as a copywriter translator

Since the C preprocessor is not based on the description of the C language, but only recognizes and processes its known him instructions, it can be used purely as a text replacement for other purposes.

Phases

The C standard defines, among other things, the following four ( out of eight ) translation phases. These four are performed by the C preprocessor:

Smuggling of file contents

The most common use of the preprocessor is to inject other file contents:

# include        int main ( void)      {          printf (" Hello, world \ n " );          return 0;      } The preprocessor replaces the line # include with the contents of the header file stdio.h, which, inter alia, the printf () function is declared. The file stdio.h is part of every C development environment.

The # include statement can also be used with double quotation marks ( # include " stdio.h "). Then, in the search for the affected file and the current directory is searched in the file system in addition to the directories of the C compiler. With options for the C compiler, the turn passes it to the C preprocessor, or by calling options for the C preprocessor can be specified, in which directories by include files to be searched.

A common convention specifies that the include files have the filename extension. H. Primary C source files have the filename extension. C. However, this is not mandatory. Also contents of files with different file name extension as. H can be introduced in this way.

Within einzuschleusender files is often caused by conditional replacement that declarations for the subsequent compiler phases be no multiple effect provided that the file contents are repeatedly introduced by # include.

Conditional replacement

The instructions # if, # ifdef, # ifndef, # else, # elif, and # endif are used for conditional substitutions of the C preprocessor:

# ifdef WIN32      # Include      # else      # Include      # endif The C preprocessor checks whether it knows a macro named WIN32. If this is the case, the file contents of is introduced, otherwise the of . The macro WIN32 can be implicitly by the translator made ​​known to carry a call option of the C preprocessor or by a command using the # define ( by all Windows 32 -bit translator, for example ).

# if VERBOSE > = 2          printf ( "control output \ n");      # endif If the macro VERBOSE through the C preprocessor has a value of 2 or greater, while its replacement, the call to the function printf is maintained, otherwise this function call is removed.

Definition and substitution of macros

In C macros without parameters, parameters, and (since C99 ) permitted with also with a variable number of parameters:

# define      # define (      # define ( ... ) Macros with parameters no white space is allowed between the macro name and the opening parenthesis. Otherwise the macro, including the list of parameters is used as raw text replacement for the macro name. To distinguish between functions which are the names of macros usually only of uppercase letters ( good programming style). An ellipsis ( "...") indicates that the macro accepted at this point one or more arguments. This reference may be made in the replacement text of the macro with the special identifier __ VA_ARGS__.

Macros without parameters will be replaced upon the occurrence of the macro name in the code by its replacement text (which may be empty). Macros with parameters that only happens if, after the macro name followed by a parameter list enclosed in parentheses and corresponds to the number of parameters of the declaration of the macro. When replacing macros with variable number of parameters the variable arguments, including the commas separating them are combined into a single argument and inserted in the replacement text instead of __ VA_ARGS__.

Macros without parameters are commonly used for symbolic names of constants:

# define PI 3.14159 An example for a macro having parameters is:

# define CELSIUS_ZU_FAHRENHEIT (t) ( (t) * 1.8 32 ) The macro CELSIUS_ZU_FAHRENHEIT describes the conversion of a temperature ( as a parameter t) from the C - to the Fahrenheit scale. Also a macro with parameters will be replaced in the source code:

Int fahrenheit, celsius = 10;      fahrenheit = CELSIUS_ZU_FAHRENHEIT ( celsius 5); is replaced by the C preprocessor to:

Int fahrenheit, celsius = 10;      fahrenheit = (( celsius 5) * 1.8 32); Macros with a variable number of parameters have to be to pass arguments to a variadic function:

# define MESSAGE (...) fprintf ( stderr, " DEBUG: " __ VA_ARGS__ ) For example:

Int i = 6, j = 9;      MESSAGE ( "i =% d, j =% d \ n", i, j ); replaced by the C preprocessor to:

Int i = 6, j = 9;      fprintf ( stderr, " DEBUG: " "i =% d, j =% d \ n", i, j ); Since C are summarized in consecutive string literals at compile time, this results in a valid call to the library function fprintf.

Macro over several lines

Since in the second phase of the C preprocessor is done by the \ character at the end of the line already bringing together on a line macros can be declared by this mechanism on several lines.

Withdraw macro definition

A previous macro definition can be done with # undef undo. This serves to make macros available only in a limited section of code:

# undef CELSIUS_ZU_FAHRENHEIT / * The scope of the macro ends here * / Conversion of a macro parameter to a string

If a parameter is preceded by a # in the replacement text of a macro, so when replacing the argument is converted by enclosing it in double quotes in a string ( Stringized ). The following program is string, not hi:

# include      # define STR ​​( X) # X        int main ( void)      {          char string [ ] = " hello";          puts ( STR (string) );          return 0;      } Concatenation of macro parameters

The concatenation operator # # allows to merge two macro parameter to a (English: token pasting ). The following sample program shows the number 234:

# include      # define Glue ( X, Y) X Y # #        int main ( void)      {          printf ("% d \ n", GLUE (2, 34) );          return 0;      } The operators # and # # enable the skilful combination of the semi- automatic creation or changing of entire parts of the program by the preprocessor during compilation of the program, but this can also lead to heavy durchschaubarem code.

Standardized macros

Two predefined macros __ FILE__ are (current filename) and __ LINE__ ( current line in the file ):

# include        # define MESSAGE (text) fprintf (stderr, \              "File [% s], line% d:% s \ n" \              __FILE__, __ LINE__, text )        if ( error)      {          MESSAGE ( " Error capital program end.. ");          exit ( EXIT_FAILURE );      } In the event of an error is output before the end of the program the following text:

File [ beispiel.c ], line 9: Error capital. End of program.

Dangers of Macros

  • It is important that when declaring macros with calculations sufficient number of brackets are placed so that always the desired result is achieved when the macro is called. If in the example of the temperature conversion brackets around the parameter t in the replacement text is not done, as would have occurred as the replacement ( mathematically wrong and not desired ) result ( celsius 5 * 1.8 32 ).
  • During macro call arguments with the operators and - as well as functions and assignments to avoid as arguments, since these undesirable due to possible multiple evaluation side effects or even undefined code can result.
  • The use of semicolons in the replacement text as the end of a C statement or as a separator between multiple specified in the macro replacement C statements should be avoided, as this can cause side effects on further to translate source code.

Selective termination of translation

With the # error of the translation process can be aborted and a message will be displayed:

# include        # if CHAR_BIT! = 8      # error "This program only supports platforms with 8-bit bytes! "      # endif Change of the file name and line number

By means of the # line directive, it is possible from the perspective of the compiler the number of the next line and also the name used for messages of the current source file to manipulate. This has implications for any subsequent compiler messages:

# line 42      / * This line would have in a compiler message now number 42 * /      # line 58 " scan.l "      / * Add a message it would be line 58 of file'' '' scan.l * / Used this mechanism is often to point of code generators such as lex or yacc in the generated C code to the corresponding part of the source file. This troubleshooting is greatly simplified.

Influence of the compiler

The preprocessor # pragma allows it to influence the compiler. Such commands are mostly compiler-specific, some defined but also the C standard (from C99 ), eg:

# include      # pragma STDC FENV_ACCESS ON      / * In the following the compiler must assume that the program         Accesses to status or mode register the floating point unit. * / literature

  • British Standards Institute (ed.): The C Standard - Incorporating TC1 - BS ISO / IEC 9899:1999. John Wiley & Sons, 2003, ISBN 0-470-84573-2, Chapter 6.10.1 to 6.10.9
  • C99 standard ISO / IEC 9899: TC3 Draft ( PDF, 3.8 MB) on www.open- std.org (English)
157644
de