Preprocessor
Home

 

The C Preprocessor

C codes are actually processed by two completely independent programs, the preprocessor (basically an automatic text editor) and the compiler

Preprocessor syntax

All preprocessor directives begin with # as the very first non-space character.  This is important - the first non-space character must be #, tabs will work with some implementations, but are not ANSI-compliant and will fail with others.  Spaces can appear before the # in ANSI C.

Preprocessor directives do not end with a semicolon like C commands.  A preprocessor directive ends with the end-of-line character, and can be continued on more than one line by hiding the carriage return with the \ character.

standard preprocessor macros

macro (N.B. 2 spaces before and after name) effect
__DATE__ current date
__FILE__ current file name
__LINE__ current line number
__STDC__ ANSI/ISO standard C compiler
__TIME__ current time

defining symbols

Preprocessor symbols might have a value, or be true or false (given C's definition of 0 as false and non-zero as true).   The following will define NROW as 10, and DEBUG as true:
#define NROW 10
#define DEBUG

Symbols can also be defined on the compiler's command line, generally with the -D option.  The following will set DEBUG to true, and NROW to 5
cc -DDEBUG -DNROW=5
Definitions of symbols that occur within the code override definitions that occur on the command line. 

Symbols are undefined (set to false) with the directive
#undef DEBUG

define vs const

The following two lines should have equivalent effects

#define NROW 10
const long NROW=10;

where the first is a preprocessor directive and the second a line of C source code.   The first ends with an end-of-line and the second with a ";".  In the second  NROW is treated as a C variable and checked for syntax, while in the first all occurrences of the string NROW are changed to the string 10.

If a variable is set with the const specifier then it can be used to declare the dimension of a vector in ISO C++, and in many C compilers.  This is not part of ISO C however and should be avoided.  The const specifier also has different meanings in C and C++ in some cases. 

Control structure

Pairs of #ifdef ... #endif directives are used to include source code depending on the values of certain symbols.  Code that should be included only when DEBUG is set would be placed between the pair, as follows:
#ifdef DEBUG
    debug code goes here
#endif

This can be expanded to #ifdef #else #endif
#ifdef DEBUG
debug code goes here
#else
production code goes here
#endif

to comment out code

/* 0 is false in C, so this test never passes.  this is the best way to comment out code.
* it is much safer than trying to comment it out with C comment commands, since that
* would not work if comments occur in the block of code you are trying to comment out */
#if 0
    printf(" never printed\n");
#endif

declaring dimension of arrays

#define NROW 10
double array[NROW];
long i;
for( i=0; i<NROW; I++ )
{
    array[i] = 0;
}

In C++ the two statements

#define NROW 10
const long NROW=10;

have similar effect, and you are able to declare arrays with them.    Notice that the define was a preprocessor directive so that all occurrences of NROW are changed to 10 before the compiler sees the source, and the const is a line of C that the compiler actually knows about.

Include files

To include files located elsewhere such as headers, use #include

#include "header.h" /* this is a user defined header, located in the user's space */
#include <header.h> /* this is a system defined header, located in a special place */

If the system responds that it cannot find a header it is necessary to tell the compiler where they are located.  This is generally done with the -Ipath option.
cc -I/usr/local/bin ...

external symbols defined

__STDC__ is true if compiler is ANSI standard C

_MSC_VER Microsoft Visual C++ compiler

Use with Fortran?

There is nothing to stop you from using the C preprocessor with Fortran too.  The preprocessor directives are removed from the code before it is sent to the compiler, so it would function as a simple text editor.  Most C systems have an option to pass code through the preprocessor only, and send the edited output to another place.  This could be a Fortran compiler.  Many Fortran systems have options to do this for you - on many systems a filename ending with ".F" will be sent through the preprocessor automatically.