The C Preprocessor

C preprocessor is exactly what its name implies. It is a program that processes our source program before it is passed to the compiler. Preprocessor commands (often known as directives) form what can almost be considered a language within C language. We can certainly write C programs without knowing anything about the preprocessor or its facilities

Features of C Preprocessor

The preprocessor offers several features called preprocessor directives. Each of these preprocessor directives begin with a # symbol. The directives can be placed anywhere in a program but are most often placed at the beginning of a program

preprocessor directives

  • Macro expansion
  • File inclusion
  • Conditional Compilation
  • Miscellaneous directives
preprocessor directives
preprocessor directives
ProcessorInputOutput
EditorProgram typed from
keyboard
C source code containing
program and preprocessor
commands
PreprocessorC source code fileSource code file with the
preprocessing commands
properly sorted out
CompilerSource code file with
preprocessing commands
sorted out
Relocatable object code
LinkerRelocatable object code
and the standard C
library functions
Executable code in
machine language
The C Preprocessor

Macro Expansion

#define UPPER 25 
main( ) 
{ 
 int i ; 
 for ( i = 1 ; i <= UPPER ; i++ ) 
 printf ( "\n%d", i ) ; 
} 

In this program instead of writing 25 in the for loop we are writing it in the form of UPPER, which has already been defined before main( ) through the statement

define UPPER 25

This statement is called ‘macro definition’ or more commonly, just a ‘macro’. What purpose does it serve ? During preprocessing, the preprocessor replaces every occurrence of UPPER in the program with 25

Macros with Arguments

The macros that we have used so far are called simple macros. Macros can have arguments, just as functions can.

#define AREA(x) ( 3.14 * x * x ) 
main( ) 
{ 
 float r1 = 6.25, r2 = 2.5, a ; 
 
 a = AREA ( r1 ) ; 
 printf ( "\nArea of circle = %f", a ) ; 
 a = AREA ( r2 ) ; 
 printf ( "\nArea of circle = %f", a ) ; 
}

Here’s the output of the program…

Area of circle = 122.656250
Area of circle = 19.625000

Macros versus Functions

In a macro call the preprocessor replaces the macro template with its macro expansion, in a stupid, unthinking, literal way. As against this, in a function call the control is passed to a function along with certain arguments, some calculations are performed in the function and a useful value is returned back from the function

File Inclusion

This directive causes one file to be included in another. The preprocessor command for file inclusion looks like this:

include “filename”

and it simply causes the entire contents of filename to be inserted into the source code at that point in the program. Of course this presumes that the file being included is existing. When and why this feature is used? It can be used in two cases:

  • If we have a very large program, the code is best divided into several different files, each containing a set of related functions. It is a good programming practice to keep different sections of a large program separate. These files are #included at the beginning of main program file
  • There are some functions and some macro definitions that we need almost in all programs that we write. These commonly needed functions and macro definitions can be stored in a file, and that file can be included in every program we write, which would add all the statements in this file to our program as if we have typed them in

It is common for the files that are to be included to have a .h extension. This extension stands for ‘header file’, possibly because it contains statements which when included go to the head of your program. The prototypes of all the library functions are grouped into different categories and then stored in different header files. For example prototypes of all mathematics related functions are stored in the header file ‘math.h’, prototypes of console input/output functions are stored in the header file ‘conio.h’, and so on.

Actually there exist two ways to write #include statement. These are:

#include "filename" 
#include <filename>

The meaning of each of these forms is given below:

include “goto.c”This command would look for the file goto.c
in the current directory as well as the
specified list of directories as mentioned in
the include search path that might have been
set up
#includeThis command would look for the file goto.c
in the specified list of directories only
File Inclusion

The include search path is nothing but a list of directories that would be searched for the file being included. Different C compilers let you set the search path in different manners. If you are using Turbo C/C++ compiler then the search path can be set up by selecting ‘Directories’ from the ‘Options’ menu. On doing this a dialog box appears. In this dialog box against ‘Include Directories’ we can specify the search path. We can also specify multiple include paths separated by ‘;’ (semicolon) as shown below:

c:\tc\lib ; c:\mylib ; d:\libfiles

The path can contain maximum of 127 characters. Both relative and absolute paths are valid. For example ‘..\dir\incfiles’ is a valid path

Conditional Compilation

We can, if we want, have the compiler skip over part of a source code by inserting the preprocessing commands #ifdef and #endif, which have the general form:

#ifdef macroname 
 statement 1 ; 
 statement 2 ; 
 statement 3 ; 
#endif 

If macroname has been #defined, the block of code will be processed as usual; otherwise not.

Example

main( ) 
{ 
 #ifdef INTEL 
 code suitable for a Intel PC 
 #else 
 code suitable for a Motorola PC 
 #endif 
 code common to both the computers 
} 

Miscellaneous Directives

There are two more preprocessor directives available, though they are not very commonly used. They are

  • #undef
  • #pragma

On some occasions it may be desirable to cause a defined name to become ‘undefined’. This can be accomplished by means of the #undef directive. In order to undefine a macro that has been earlier #defined, the directive

#undef macro template 
can be used. Thus the statement, 
#undef PENTIUM

would cause the definition of PENTIUM to be removed from the system

#pragma Directive

This directive is another special-purpose directive that you can use to turn on or off certain features. Pragmas vary from one compiler to another. There are certain pragmas available with Microsoft C compiler that deal with formatting source listings and placing comments in the object file generated by the compiler. Turbo C/C++ compiler has got a pragma that allows you to suppress warnings generated by the compiler

Example

void fun1( ) ; 
void fun2( ) ; 
#pragma startup fun1 
#pragma exit fun2 
main( ) 
{ 
 printf ( "\nInside maim" ) ; 
} 
void fun1( ) 
{ 
 printf ( "\nInside fun1" ) ; 
} 
void fun2( ) 
{ 
 printf ( "\nInside fun2" ) ; 
}

And here is the output of the program.

Inside fun1
Inside main
Inside fun2

Note that the functions fun1( ) and fun2( ) should neither receive nor return any value. If we want two functions to get executed at startup then their pragmas should be defined in the reverse order in which you want to get them called.

Leave a Comment