Preprocessor Directives In C - Online Article

The preprocessor is a program that is invoked by the compiler to process code before compilation. Commands for that program, known as directives, are lines of the source file beginning with the character #, which distinguishes them from lines of source program text. The effect of each preprocessor directive is a change to the text of the source code, and the result is a new source code file, which does not contain the directives. The preprocessed source code, an intermediate file, must be avalid C or C++ program, because it becomes the input to the compiler.

Introduction

The C Preprocessor is exactly what its name implies. It is a program that processesor source program before it is passed to the compiler. Preprocessor commands(often known is directives) form what can almost be considered a language within C language.

Features of C Preprocessor

There are several steps involved from the stage of writing a C Program to the stage of getting it executed. The combinations of these steps is known as the ‘Build Process’. At this stage it would be sufficient to note that before a c program is compiled it is passed through another program called ‘Preprocessor’. The Preprocessor works on the source code and creates ‘Expanded Source code’.

The preprocessor offers several features called preprocessor directives. Each of these preprocessor directives begins with a # symbol. The directives can be placed anywhere in a program. Often placed at the beginning of a program, before the first function definition. wewould learn the following preprocessor directives here:

     
  1. Marco Expansion 
  2. File Inclusion 
  3. Conditional Compilation 
  4. Miscellaneous Directives

Let us understand there features of preprocessor one by one:

Marco Expansion

Have a look at the following program

# include<stdio.h>
# define UPPER 25void main( )
{
  int i;
  for(i=1 ; i<= UPPER; i ++)
  printf(“\n%d”, i );
}

In this program, instead of writing 25 inthe 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 ‘marco definition’ or more commonly, just a ‘marco’.

Example:

#include<stdio.h>
# define PI 3.145void main( )
{
  float r = 6.25;
  float area;
  area = PI*r*r;
  printf(“\n Area of Circle = %f ”, area);
}

UPPER and PI in the above programs are often called ‘marco templates’, whereas, 25 and 3.1415 are called their corresponding ‘marco expansions’.

When we compile the program, before the source code passes to the compiler, it is examined by the C preprocessor for any macro definitions.

When it sees the #define directive, it goes through the entire program in search of the marco templates.

Note: A marco template and its marco expansion are separated by blanks or tabs. A space   between # and define is optional. Remember that a marco definition is never tobe terminated by a semicolon.

Thus, using #define can produce more efficient and more easily understand programs. This directive is used extensively by C Programmers. Following three examples show places where a #define directive is popularly used by C Programmers.

Examples : 248, 249 page Enter here

Macro with Arguments

The macros that we have used so far are called simple macros. Marcos can have arguments, just as functions can. Here is an example.

Define a macro called SQR which squares a number.   This is the wrong way of doing it.

#define SQR(x) (x * x)

This is the right way of doing it.

#define SQR(x) ((x) * (x))

What happens if you include unwanted headers?
  You will end up increasing the size of your executables!

Example: Is there a limit on the number of characters in the name of a header file?

The limitation is only that identifiers be significant in the first six characters, not that they be restricted to six characters in length.

Example:

#include<stdio.h>
#define FOUND
printf(“ The Yankee Doodle Virus”);
void main( )
{
  char signature
  if (signature = = ‘Y’ )
  FOUND
  else
  printf( “Safe … as yet ! ” ) ;
}

File Inclusion

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

#include “file name”

This presumes that the file being included exists when and why this feature is used ? It can be used in two cases:

     
  1. If we have a very large program., the code is best divided into several different files, each containing a set of related functions. These files are #include at the beginning of main program file. 
  2. There are some functions and some macro definitions that we need almost in all programs that we write. There commonly needed functions and marco definitions can be stored in a file and that file can be included in every program.

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

#include “file name”
#include <file name>
#include “ goto.h”: This command would look for the file goto.hin the current directory
  as well as the specified list of directories.
#include < goto.h>: This command would look for the file goto.hin the specified list of
  directories.

Conditional Compilation

We can, if we want, have the compilers skip over part of a source code by inserting the preprocessing commands #if defand #end if

Syntax:

# if def marconame.
Statement1;
Statement2;
Statement3;
# endif

The solution is to useconditional compilation as shown below.

void main( )
{
# ifdef OKAY
Statement 1;
Statement 2;
Statement 3;
Statement4;
#endif
Statement5;
Statement6;
Statement7;
}

#if and #elif directives:

The #if directive can be used to test whether an expression evaluates to a non-zero value or not . If the result of the expression is non-zero, then subscript lines upto a #else , #elif or #endif are compiled, otherwise they are skipped.

Example:

void main( )
{
#if TEST<=5
Statement 1;
Statement 2;
Statement 3;
#else
Statement 4;
Statement 5;
Statement 6;
#endif
}

We can have nested conditional compilation directives an example that use such directives is shown below.

#if ADAPTER = = VGA

Code for video graphics array

#else
#if ADAPTER = = SVGA

Code for super video graphics array

#else

Code for extended graphics adapter

#endif
#endif

What purpose do #if, #else,#elif, #endif, #ifdef, #ifndef serve?

The following preprocessor directives are used for conditional compilation. Conditional compilation allows statements to be included or omitted based on conditions at compile time.

#if
#else
#elif
#endif
#ifdef
#ifndef

In the following example, the printf statements are compiled when the symbol DEBUG is defined, but not compiled otherwise

/* remove to suppress debug printf's*/
#define DEBUG
...
x = ....
#ifdef DEBUG
printf( "x=%d\n" );
#endif
...
y = ....;
#ifdef DEBUG
printf( "y=%d\n" );
#endif
...
#if, #else, #elif statements

#if directive

  • #if is followed by a integer constant expression.
  • If the expression is not zero, the statement(s) following the #if are compiled, otherwise they are ignored.
  • #if statements are bounded by a matching #endif, #else or #elif 
  • Macros, if any, are expanded, and any undefined tokens are replaced with 0 before the constant expression is evaluated.
  • Relational operators and integer operators may be used.

Expression Examples

#if 1
#if 0
#if ABE == 3
#if ZOO < 12
#if ZIP == 'g'
#if (ABE + 2 - 3 * ZIP) > (ZIP - 2)
In most uses, expression is simple relational, often equality test
#if SPARKY == '7'

#else directive

  1. #else marks the beginning of statement(s) to be compiled if the preceding #if or #elif expression is zero (false) 
  2. Statements following #else are bounded by matching #endif

Example:

#if OS = 'A'
  system( "clear" );
#else
  system( "cls" );
#endif

#elif directive

  • #elif adds an else-if branch to a previous #if
  • A series of #elif's provides a case-select type of structure
  • Statement(s) following the #elif are compiled if the expression is not zero, ignored otherwise.
  • Expression is evaluated just like for #if
Example
 
#if TST == 1
  z = fn1( y );
  #elif TST == 2
  z = fn2( y, x );
  #elif TST == 3
  z = fn3( y, z, w );
  #endif
  ...
  #if ZIP == 'g'
  rc = gzip( fn );
  #elif ZIP == 'q'
  rc = qzip( fn );
  #else
  rc = zip( fn );
#endif

#ifdefand #ifndef directives

Testing for defined macros with#ifdef,#ifndef,and defined()

  • #ifdef is used to include or omit statements from compilation depending of whether a macro name is defined or not.
  • Often used to allow the same source module to be compiled in different environments (UNIX/ DOS/MVS), or with different options (development/production).
  • #ifndef similar, but includes code when macro name is not defined.

Examples

#ifdef TESTENV    printf( "%d ", i );   
#endif
  #ifndef DOS
  #define LOGFL "/tmp/loga.b";
  #else
  #define LOGFL "c:\\tmp\\log.b";
#endif

defined()operator

  • defined(ma3., operator is used with #if and #elif and gives 1 (true) if macro name mac is defined, 0 (false) otherwise.

Equivalent to using #ifdef and#ifndef, but many shops prefer #if with defined (ma3. or   !defined(ma3.

Examples

#if defined(TESTENV)
  printf( "%d ", i );
  #endif
  #if !defined(DOS)
  #define LOGFL "/tmp/loga.b";
  #else
  #define LOGFL "c:\\tmp\\log.b";
  #endif

Nestingconditional statements

Conditional compilation structures may be nested:

  #if defined(UNIX)
  #if LOGGING == 'y'
  #define LOGFL "/tmp/err.log"
  #else   #define LOGFL "/dev/null"
  #endif
  #elif defined( MVS )
  #if LOGGING == 'y'
  #define LOGFL "TAP.AVS.LOG"
  #else
  #define LOGFL "NULLFILE"
  #endif
  #elif defined( DOS )
  #if LOGGING == 'y'
  #define LOGFL "C:\\tmp\\err.log"
  #else
  #define LOGFL "nul"
  #endif
  #endif

Miscellaneous Directives

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

#undef

On some occasion, it may be desirable to cause a defined name to because ‘undefined’.This can be accomplished by means of the # undef directive.

 #undef macro templates

Can be used .thus thestatement.

 #undef  PENTIUM

Would cause the definition of PENTIUM tobe removed from the system. All subsequent # if def PENTIUM statements wouldevaluates to false.

#pragma

This directive is another special purpose directive that you can use to turn on or off certain features. Pragmas very from one compiler to another. There are certain pragmas available with Microsoft C compiler that deal with formatting source listing and placing comments in the object file generated by the compiler.

# pragma startup and #pragma exit

These directives allow us to specify function that are called upon program startup (before main( )) orprogram exit (just before the program terminates).

Example

voidfun1( );
voidfun2( );
#pragmastartup fun1
#pragmaexit fun2
voidmain( ){printf(“\nInside main”);}
voidfun1( ){printf(“\nInside fun1”);}
voidfun2( ){printf(“\nInside fun2”);}

Output:

Insidefun1
Insidemain
Insidefun2
Inside main
Note:
The functionfun1( ) and fun( ) should neither receive nor return any value.

#pragma warn

On compilation the compiler reports errors and warnings in the programs, if any. Errors provide the programmer with no options, apart from correcting them. Warnings, on the other hand, offer the programmer a hint or suggestion that something may be wrong with a particular piece of code .Two most common situation when warning are displayed.

  1. If you have written code that the compiler’s designers(or the ANSI-C specification) consider bad C programming practice. For ex: if a function does not return a value then it should be declared as void.
  2. If you have written code that night cause run-time errors, such as assigning a valueto an uninitialized pointer.

Example: 264, 265 enter here

The Build Process

There are many steps involved in converting a C Program into an executable form. These different steps along with the files created during each stage.

Processor

Input

Output

Editor

Program typed from Keyword

C source code containing program

Preprocessor

C source code file

Intermediate source code

Compiler

Intermediate source code

Assembly language code

Assembler

Assembly language code

Relocatable Object code in machine language

Linker

Object code of our program and object code of library functions

Executable code in machine

Language

Loader

Executable file

About the Author:

No further information.




Comments

h a on 2009-05-26 06:33:19 wrote,

good job