C - Preprocessors: Direc Tive Desc Ription
C - Preprocessors: Direc Tive Desc Ription
T he C Preproc essor is not part of the compiler, but is a separate step in the compilation process. In simplistic terms, a C Preprocessor is just a text substitution tool and they instruct compiler to do required pre-processing before actual compilation. We'll refer to the C Preprocessor as the CPP. All preprocessor commands beg in with a pound symbol (#). It must be the first nonblank character, and for readability, a preprocessor directive should beg in in first column. Following section lists down all important preprocessor directives:
Direc tive #define #include #undef #ifdef #ifndef #if #else #elif #endif #error #prag ma
Desc ription Substitutes a preprocessor macro Inserts a particular header from another file Undefines a preprocessor macro Returns true if this macro is defined Returns true if this macro is not defined T ests if a compile time condition is true T he alternative for #if #else an #if in one statement Ends preprocessor conditional Prints error messag e on stderr Issues special commands to the compiler, using a standardized method
Preprocessors Examples
Analyze the following examples to understand various directives.
#define MAX_ARRAY_LENGTH 20
T his directive tells the CPP to replace instances of MAX_ARRAY_LENGT H with 20. Use #define for constants to increase readability.
#include <stdio.h> #include "myheader.h"
T hese directives tell the CPP to g et stdio.h from System Libraries and add the text to the current source file. T he next line tells CPP to g et myheader.h from the local directory and add the content to the current source file.
#undef FILE_SIZE #define FILE_SIZE 42
T his tells the CPP to undefine existing FILE_SIZ E and define it as 42.
#ifndef MESSAGE #define MESSAGE "You wish!" #endif
T his tells the CPP to define MESSAGE only if MESSAGE isn't already defined.
#ifdef DEBUG /* Your debugging statements here */ #endif
T his tells the CPP to do the process the statements enclosed if DEBUG is defined. T his is useful if you pass the DDEBUG flag to g cc compiler at the time of compilation. T his will define DEBUG, so you can turn debug g ing on and off on the fly during compilation.
Predefined Macros
ANSI C defines a number of macros. Althoug h each one is available for your use in prog ramming , the predefined macros should not be directly modified.
Desc ription T he current date as a character literal in "MMM DD YYYY" format T he current time as a character literal in "HH:MM:SS" format T his contains the current filename as a string literal. T his contains the current line number as a decimal constant. Defined as 1 when the compiler complies with the ANSI standard.
); ); ); ); );
When the above code in a file test.c is compiled and executed, it produces the following result:
File Date Time Line ANSI :test.c :Jun 2 2012 :03:36:24 :8 :1
Preprocessor Operators
T he C preprocessor offers following operators to help you in creating macros:
Mac ro Co ntinuatio n (\)
A macro usually must be contained on a sing le line. T he macro continuation operator is used to continue a macro that is too long for a sing le line. For example:
#define message_for(a, b) \ printf(#a " and " #b ": We love you!\n")
S tring iz e (#)
T he string ize or number-sig n operator ('#'), when used within a macro definition, converts a macro parameter into a string constant. T his operator may be used only in a macro that has a specified arg ument or parameter list. For example:
#include <stdio.h> #define message_for(a, b) \ printf(#a " and " #b ": We love you!\n") int main(void) { message_for(Carole, Debra); return 0; }
When the above code is compiled and executed, it produces the following result:
Carole and Debra: We love you! T o ken Pasting (##)
T he token-pasting operator (##) within a macro definition combines two arg uments. It permits two separate tokens in the macro definition to be joined into a sing le token. For example:
#include <stdio.h> #define tokenpaster(n) printf ("token" #n " = %d", token##n) int main(void) { int token34 = 40; tokenpaster(34); return 0; }
When the above code is compiled and executed, it produces the following result:
token34 = 40
How it happened, because this example results in the following actual output from the preprocessor:
printf ("token34 = %d", token34);
T his example shows the concatenation of token##n into token34 and here we have used both string ize and token-pasting .
T he defined() O perato r
T he preprocessor defined operator is used in constant expressions to determine if an identifier is defined using #define. If the specified identifier is defined, the value is true (non-zero). If the symbol is not defined, the value is false (zero). T he defined operator is specified as follows:
#include <stdio.h> #if !defined (MESSAGE) #define MESSAGE "You wish!" #endif int main(void) { printf("Here is the message: %s\n", MESSAGE);
return 0; }
When the above code is compiled and executed, it produces the following result:
Here is the message: You wish!
Parameterized Macros
One of the powerful functions of the CPP is the ability to simulate functions using parameterized macros. For example, we mig ht have some code to square a number as follows:
int square(int x) { return x * x; }
Macros with arg uments must be defined using the #define directive before they can be used. T he arg ument list is enclosed in parentheses and must immediately follow the macro name. Spaces are not allowed between and macro name and open parenthesis. For example:
#include <stdio.h> #define MAX(x,y) ((x) > (y) ? (x) : (y)) int main(void) { printf("Max between 20 and 10 is %d\n", MAX(10, 20)); return 0; }
When the above code is compiled and executed, it produces the following result:
Max between 20 and 10 is 20