Search This Blog

Saturday, May 26, 2012

The C – Preprocessor


The C – Preprocessor
The preprocessor is a program that processes the source code before it passes through the compiler. It operates under the control of preprocessor command line or directives. Preprossor directives are placed in the source program before the main line. Before the source code passes through the compiler, it is examined by preprocessor. After taking appropriate actions as directed by preprocessor, the source program is handed over to the compiler.

            The syntax of preprocessor directives begin with the symbol #  and donot require semi colon (;)  at the end. The preprocessor directives can be divided into three categories.
  1. Macro substitution
  2. File Inclusion
  3. Compiler control Directives

1. Macro Substitution:
            In macro substitution, an IDENTIFIER  is replaced by pre-defined string. The preprocessor accomplishes this job under the direction of  #define directives which is called macro. The syntax for macro definition is:

 #define  IDENTIFIER  string

            If this line is included at the beginning of the program, preprocessor replaces IDENTIFIER in source code by string defined in macro. The IDENTIFIER must be C valid name.
There are three different forms of macro substitutions:
a.       Simple macro substitution
b.      Arguemented  macro substitution
c.       Nested macro substitution

èA simple macro:
         A simple macro  is generally used to define symbolic constants.
   example:
#define PI  3.14159
         #define      TRUE  1
         #define       CITY    “Kathmandu
         #define       TWO_PI       2*(22/7)
         #define       BLANK_LINE     printf(“\n”);
         #define       INCREMENT   ++
         #define       START     {
         #define       END       }                                      etc.
The Uppercase letter for IDENTIFIER is conventions for defining Constants.


è Arguemented  macro :

We can define complex macro with arguments. The syntax is
    #define     IDENTIFIER(a1,a2,…..,an)    string
ü  There is no space between IDENTIFIER  and parenthesis .
ü  a1,a2,….,an are macro formal parameters.
ü  When   a macro is called , the preprocessor substitutes the string, replacing the formal parameters with actual parameters( passed when calling macro )
Example:
#define       SQUARE(x) ((x)*(x))
#define       CUBE(x)   ((x)*(x)*(x))
 We can call these macro in our source program as
            Area = PI*SQUARE(radius);
Which is equivalent to :
            Area = PI*((radius)*(radius));        /*substitution of macro */
Other examples of arguemented macro:
     #define       MAX(a,b)     (((a)>(b))? (a): (b))
     #define       MIN(a,b)     (((a)<(b))? (a) : (b))
     #define       MODVAL(x)     (((x)>0) ? (x) : (-(x)))
     #define       RECIPROCAL(x) (1.0/(x))                              etc.

è Nesting macro:
                We can use one pre-defined macro to define new macro. This is called nesting of macro definition.
Example:
            #define                        PI        3.14159
            #define                        TWO_PI         2*PI
            #define                        SQUARE(x)   ((x)*(x))
            #define                        CUBE(x)         ((x)*SQUARE(x))
            #define                        SIX_POWER(x)         ((CUBE(x))*(CUBE(x)))
ü  Given the definition of macro MAX(a,b) , We can use nested call of macro to fine maximum of three numbers a,b,c as:
          MAX(a,MAX(a,b))
  • To define multiple lines we can use \ character at the end of each line:
Undifining a Macro:

 A defined macro can be undefined , using the statement:
          #undef   IDENTIFIER
it is useful when to restrict the definition only to a particular part of the program.


2. File inclusion directives:   (#include directives)
            A file which contains the pre-defined macros and functions can be included in our source program using #include directive. If we include  pre-written file in our source program we need not to rewrite the functions and macro which are defined in that file.
The syntax for file inclusion directive is :
 #include<filename>               or         #include “filename”
è When #include<filename> is used, the file inside <  > is searched  in the standard directory and included in the source program where it is written. If file is not find an error is reported.
è When #include “filename” is used , the file inside “     ” is  searched first in the current directory and then standard directory  included in the source program where it is written. If file is not find an error is reported.

A simple example of file inclusion:

 Consider a file  named  test.c which includes the definition of functions for square and cube and macro to find the maximum of two numbers , and  constant PI.

/*  test.c */

#define  PI    3.14
#define  MAX(x,y)   ( ( (x) > (y) ) ? (x) : (y) )

int square(int x) /*square function */
{
  return x*x;
}

int cube(int x)    /*cube function */
{
  return (x*x*x);
}

Now we have to write a program that uses functions and macros defined in  test.c. the source program is as:
/*source.c */
#include<stdio.h>
#include “test.c”
void main()
{
   int x =10, y=20;
   printf(“\nThe square of %d is %d” , x, square(x));
   printf(“\nThe cube of %d is %d “, x, cube(x));
   printf(“\n The larger no is %d.”, MAX(a,b));
}

when we run the source file source.c the output will be
The square of 10 is 100
The cube of 10 is 1000
 The larger no is 20.
3.  Compiler control directives(Conditional Compilation)
                  Conditional compilation enables the programmer to control the execution of preprocessor directive and the compilation of the program code. Each of the conditional preprocessor directive evaluates a conatant integer expression.
      The conditional preprocessor directive construct is similar to if-else construct. The conditional compilation can be done using #if, #elif ,#else, #ifdef  ,#ifndef.
Examples:
 #if defined(NULL)
 #undef NULL
 #endif
 This can be equivalently defined as :
#ifdef     NULL
#undef   NULL
#endif
This conditional directives search for the definition of NULL in the current header file and source file if it is defined then it is undefined.
Similarly:
#if !defined(NULL)
#define NULL 0
#endif

                   or equivalently,
   #ifndef    NULL
   #define  NULL    0
   #endif

 This conditional directives search for the definition of NULL in the current header file and source file if it is not defined then it is defined to 0.In the above directives, if line evaluates the constant integer expression. If expression is non-zero, subsequent lines until #endif are included.

For multiple selection  of lines to include, #elif, #else can be used as else if and else in selection structures. Suppose  there is different versions of header file for different systems. To decide which version of a header file to include, we can write preprocessor directive as:

#if    SYSTEM ==  SYSV
     #define      HDR    “sysv.h”
#elif  SYSTEM ==  BSD
     #define   HDR    “bsc.h”
#elif  SYSTEM ==  MSDOS
     #define    HDR    “msdos.h”
#else
     #define    HDR   “default.h”
#endif

#include  HDR

Some Pre defined macros

ANSI C has five pre defined macros. These macros can not be undefined or redefined by programmer . Each of these macros name include two leading and two trailing underscore ‘_’  characters.
1. __DATE__             A string containing the current date of the form “Mmm  dd  yyyy”
2. __TIME__              A string containing the current time of the form “hh:mm:ss”
3. __LINE__               The line number of the current source code line
4. __FILE__               The file name of the current source file
5.__STDC__               If implementation follows ANSI standard of C then  value is non zero.


Try the following Code in your program:
printf(“\n__DATE__ = %s”, __DATE__);
printf(“\n__TIME__ = %s”, __TIME__);
printf(“\n__LINE__ = %s”,__LINE__);
printf(“\n__FILE__ =  %s”, __FILE__);
printf(“\n__STDC__ = %s”,__STDC__);

No comments:

Post a Comment