0% found this document useful (0 votes)
14 views

C Preprocessor

Uploaded by

bojodis702
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views

C Preprocessor

Uploaded by

bojodis702
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

C preprocessor

C preprocessor 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. All preprocessor commands begin with a hash symbol (#).
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 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, before the first function definition. We would learn the following preprocessor directives
here:
(a) Macro expansion
(b) File inclusion
(c) Conditional Compilation

Macro Expansion
Have a look at the following program.
#define LIMIT 20
main( )
{
int i ;
for ( i = 1 ; i <= LIMIT ; i++ )
printf ( "\n%d", i ) ;
}
In the above program instead of writing 20 in the for loop we are writing it in the form of LIMIT, which has already
been defined before main( ) through the statement,
#define LIMIT 20
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 LIMIT in the program with 20. 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 ) ;
}
LIMIT and PI in the above programs are often called ‘macro templates’, whereas, 20 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. Only after this procedure has been completed is the program handed over to
the compiler.
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. Note that a macro template and its macro
expansion are separated by blanks or tabs. A space between # and define is optional. Remember that a macro
definition is never to be terminated by asemicolon.

And now a million dollar question... why use #define in the above programs? What have we gained by substituting
PI for 3.1415 in our program? Suppose a constant like 3.1415 appears many times in your program. This value may
have to be changed some day to 3.141592. Ordinarily, you would need to go through the program and manually
change each occurrence of the constant. However, if you have defined PI in a #define directive, you only need to
make one change, in the #define directive itself: #define PI 3.141592
Beyond this the change will be made automatically to all occurrences of PI before the beginning of compilation. In
short, it is nice to know that you would be able to change values of a constant at all the places in the program by
just making a change in the #define directive. This convenience may not matter for small programs shown above,
but with large programs macro definitions are almost indispensable.Following three examples show places where
a #define directive is popularly used by C programmers.
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" ) ;
}

A #define directive could be used to replace even an entire C statement. This is shown below.
#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 the above program wherever the preprocessor finds the phrase AREA(x) it expands it into the statement
( 3.14 * x * x ).However, that’s not all that it does. The x in the macro template AREA(x) is an argument that
matches the x in the macro expansion ( 3.14 * x * x ). The statement AREA(r1) in the program causes the variable
r1 to be substituted for x. Thus the statement AREA(r1) is equivalent to:( 3.14 * r1 * r1 )
After the above source code has passed through the preprocessor, what the compiler gets to work on will be this:

main( )
{
float r1 = 6.25, r2 = 2.5, a ;
a = 3.14 * r1 *r1 ;
printf ( "Area of circle = %f\n", a ) ;
a = 3.14 *r2 * r2 ;
printf ( "Area of circle = %f", a ) ;
}

Here is another example of macros with arguments:


#define ISDIGIT(y) ( y >= 48 && y <= 57 )
main( )
{
char ch ;
printf ( "Enter any digit " ) ;
scanf ( "%c", &ch ) ;
if ( ISDIGIT ( ch ) )
printf ( "\nYou entered a digit" ) ;
else
printf ( "\nIllegal input" ) ;
}

Here are some important points to remember while writing macros with arguments:

• Be careful not to leave a blank between the macro template and its argument while defining the macro.
For example, there should be no blank between AREA and (x) in the definition,
#define AREA(x) ( 3.14 * x * x )
If we were to write AREA (x) instead of AREA(x), the (x) would become a part of macro expansion, which
we certainly don’t want. What would happen is, the template would be expanded to ( r1 ) ( 3.14 * r1 * r1
)which won’t run. Not at all what we wanted.
• The entire macro expansion should be enclosed within parentheses. Here is an example of what would
happen if we fail to enclose the macro expansion within parentheses.

#define SQUARE(n) n * n
main( )
{
int j ;
j = 64 / SQUARE ( 4 ) ;
printf ( "j = %d", j ) ;
}
The output of the above program would be:
j = 64
whereas, what we expected was j = 4.

What went wrong? The macro was expanded into


j = 64 / 4 * 4 ;
which yielded 64.

• Macros can be split into multiple lines, with a ‘\’ (back slash) present at the end of each line. Following
program shows how we can define and use multiple line macros.

#define HLINE for ( i = 0 ; i < 79 ; i++ ) \


printf ( "%c", 196 ) ;
#define VLINE( X, Y ) {\
gotoxy ( X, Y );\
printf ( "%c", 179 ) ; \
}
Void main
{
int i, y ;
clrscr( ) ;
gotoxy ( 1, 12 ) ;
HLINE
for ( y = 1 ; y < 25 ; y++ )
VLINE ( 39, y ) ;
}
This program draws a vertical and a horizontal line in the center of the screen.
Macros versus Functions
• Macros are pre-processed which means that all the macros would be processed before your program
compiles. However, functions are not preprocessed but compiled.
• In macro there is no type checking.In function there is type checking.
• Macros Speed of execution is faster than function.
• Macro does not Check Compile Errors but Function Checks Compile Errors.

File Inclusion
The second preprocessor directive we’ll explore in this chapter is file inclusion. This directive causes one file to be
included in another. The preprocessor command for file inclusion looks like
this: #include "filename"
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 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.
#include <goto.c> This command would look for the file goto.c in the specified list of
directories only.
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
Conditional compilation as the name implies that the code is compiled if certain condition(s) hold true. Normally
we use if keyword for checking some condition so we have to use something different so that compiler can
determine whether to compile the code or not. The different thing is #if.

#include <stdio.h>
#define x 10

int main()
{
#ifdef x
printf("hello\n"); // this is compiled as x is defined
#else
printf("bye\n"); // this isn't compiled
#endif

return 0;
}

O/P hello

#include <stdio.h>
int main()
{
#ifdef x
printf("hello\n"); // this will not compiled
#else
printf("bye\n"); // this will compiled
#endif

return 0;
}

O/P-bye

#include <stdio.h>
int main()
{
#define COMPUTER "An amazing device"

#ifdef COMPUTER
printf(COMPUTER);
#endif

return 0;
}

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:
Void main( )
{
#if TEST <= 10
statement 1 ;
statement 2 ;
#else
statement 3 ;
statement 4;
#endif
}
O/P- statement1 and statement 2

If the expression, TEST <= 10 evaluates to true then statements 1and 2 are compiled otherwise statements 3and 4
are compiled.
#define TEST 15
Void main( )
{
#if TEST <= 10
statement 1 ;
statement 2 ;
#else
statement 3 ;
statement 4;
#endif
}
O/P- statement3 and statement4

You might also like