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.
Features of C preprocessor :
The preprocessor offers several features called preprocessorvdirectives.
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,
before the first function definition.
We would learn the following preprocessor directives here:
(a) Macro expansion
(b) File inclusion
Macro Expansion :
Have a look at the following program.
#include <stdio.h>
#include <conio.h>
#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.
Here is another example of macro definition.
#define PI 3.1415
main( )
{
float r = 6.25 ;
float area ;
area = PI * r * r ;
printf ( "\nArea of circle = %f", area ) ;
}
UPPER and PI in the above programs are often called ‘macro templates’,
whereas, 25 and 3.1415 are called their corresponding ‘macro 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
macro templates ,wherever it finds one, it replaces the macro template with the appropriate macro expansion.
In C programming it is customary to use capital letters for macro template. This makes it easy for programmers to pick out all the macro templates when reading through the program.
A #define directive is many a times used to define operators as shown below.
#define AND &&
#define OR ||
main( )
{
int f = 1, x = 4, y = 90 ;
if ( ( f < 5 ) AND ( x <= 20 OR y <= 45 ) )
printf ( "\nYour PC will always work fine..." ) ;
else
printf ( "\nIn front of the maintenance man" ) ;
}
A #define directive could be used even to replace a condition, as
shown below.
#define AND &&
#define ARANGE ( a > 25 AND a < 50 )
main( )
{
int a = 30 ;
if ( ARANGE )
printf ( "within range" ) ;
else
printf ( "out of range" ) ;
}
#define FOUND printf ( "The Yankee Doodle Virus" ) ;
main( )
{
char signature ;
if ( signature == 'Y' )
FOUND
else
printf ( "Safe... as yet !" ) ;
}
Macros with Arguments :
The macros that we have used so far are called simple macros.
Macros can have arguments, just as functions can. Here is an example that illustrates this fact.
#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
In this program wherever the preprocessor finds the phrase AREA(x) it expands it into the statement ( 3.14 * x * x ).
Macros versus Functions
In the above example a macro was used to calculate the area of the circle.
As we know, even a function can be written to calculate the area of the circle.
Though macro calls are ‘like’ function calls, they are not really the same things.
Then what is the difference between the two?
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.
This brings us to a question: when is it best to use macros with arguments and when is it better to use a function?
Usually macros make the program run faster but increase the program size,
whereas functions make the program smaller and compact.
If we use a macro hundred times in a program, the macro expansion goes into our source code at hundred different places, thus increasing the program size.
On the other hand, if a function is used, then even if it is called from hundred different places in the program, it would take the same amount of space in the program.
But passing arguments to a function and getting back the returned value does take time and would therefore slow down the program.
This gets avoided with macros since they have already been expanded and placed in the source code before compilation.
Conclusion :
If the macro is simple and sweet like in our examples, it makes nice shorthand and avoids the overheads associated with function calls. On the other hand, if we have a fairly large macro and it is used fairly often, perhaps we ought to replace it with a function.
File Inclusion :
The second preprocessor directive we’ll is 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:
(a) 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.
(b) There are some functions and some macro definitions that weneed 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.
#if and #elif Directives :
The #if directive can be used to test whether an expression evaluates to a nonzero value or not. If the result of the expression is nonzero, then subsequent lines upto
a #else, #elif or #endif are compiled, otherwise they are skipped.
A simple example of #if directive is shown below:
main( )
{
#if TEST <= 5
statement 1 ;
statement 2 ;
statement 3 ;
#else
statement 4 ;
statement 5 ;
statement 6 ;
#endif
}
If the expression, TEST <= 5 evaluates to true then statements 1, 2 and 3 are compiled otherwise statements 4, 5 and 6 are compiled.
Prev NEXT
0 comments:
Post a Comment