The Preprocessor Directive
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 a valid C or C++ program because it becomes the input to the compiler.
Preprocessor directives consist of the following:
- Macro definition directives, which replace tokens in the current file with specified replacement tokens.
- File inclusion directives, which imbed files within the current file.
- Conditional compilation directives, which conditionally compile sections of the current file.
- Message generation directives, which control the generation of diagnostic messages.
Macro definition directives
Macro definition directives include the following directives and operators:
- The #define directive, which defines a macro
- The #undef directive, which removes a macro definition
The #define directive
A Tpreprocessor define directiveT directs the preprocessor to replace all subsequent occurrences of a macro with specified replacement tokens.
The T#defineT directive can contain:
- Object-like macros
- Function-like macros
Object like Macros
An object-like macro definition replaces a single identifier with the specified replacement tokens.The following object-like definition causes the preprocessor to replace all subsequent instances of the identifier COUNT with the constant 1000.
#define COUNT 1000
Function-like macros
More complex than object-like macros, a function-like macro definition declares the names of formal parameters within parentheses, separated by commas. An empty formal parameter list is legal: such a macro can be used to simulate a function that takes no arguments.
#define SUM(a,b) (a + b)
This definition would cause the preprocessor to change the following statements (if the statements appear after the previous definition):
c = SUM(x,y); c = d * SUM(x,y);
In the output of the preprocessor, these statements would appear as:
c = (x + y); c = d * (x + y);
Use parentheses to ensure correct evaluation of replacement text.
#undef directive
A Tpreprocessor undef directiveT causes the preprocessor to end the scope of a preprocessor definition. If the identifier is not currently defined as a macro, T#undefT is ignored.The following directives define TBUFFERT and TSQRT:
#define BUFFER 512 #define SQR(x) ((x) * (x))
The following directives nullify these definitions:
#undef BUFFER #undef SQR
File inclusion directives
The #include directive allows external header files to be processed by the compiler.Syntax:
#include <header-file>
Or
#include "source-file"
When enclosing the file with, then the implementation searches the known header directories for the file (which is implementation-defined) and processes it. When enclosed with double quotation marks, then the entire contents of the source-file is replaced at this point. The searching manner for the file is implementation-specific.
Examples:
#include <stdio.h> #include "my_header.h"
Conditional compilation directive
It causes the preprocessor to conditionally suppress the compilation of portions of source code.These directives test a constant expression or an identifier to determine which tokens the preprocessor should pass on to the compiler and which tokens should be bypassed during preprocessing. The directives are:
- The #if and #elif directives, which conditionally include or suppress portions of source code, depending on the result of a constant expression.
- The #ifdef directive, which conditionally includes source text if a macro name is defined
- The #ifndef directive, which conditionally includes source text if a macro name is not defined.
- The #else directive, which conditionally includes source text if the previous T#ifT, T#ifdefT, T#ifndefT, or T#elifT test fails.
- The #endif directive, which ends conditional text.
The #if and #elif directives
The T#ifT and T#elifT directives compare the value of Tconstant_expressionT to zero. If the constant expression evaluates to a nonzero value, the lines of code that immediately follow the condition are passed on to the compiler.
If the expression evaluates to zero and the conditional compilation directive contains a preprocessor T#elifT directive, the source text located between the T#elifT and the next T#elifT or preprocessor T#elseT directive is selected by the preprocessor to be passed on to the compiler. The T#elifT directive cannot appear after the preprocessor T#elseT directive.
#if OS==1 printf("Version 1.0"); #elif OS==2 printf("Version 2.0"); #else printf("Version unknown"); #endif
Prints according to the setting of OS which is defined with a #define.
The #ifdef directive
The T#ifdefT directive checks for the existence of macro definitions. If the identifier specified is defined as a macro, the lines of code that immediately follow the condition are passed on to the compiler.
The following example defines TMAX_LENT to be T75T if TEXTENDEDT is defined for the preprocessor. Otherwise, TMAX_LENT is defined to be T50T.
#ifdef EXTENDED # define MAX_LEN 75 #else # define MAX_LEN 50 #endif
The #ifndef directive
The T#ifndefT directive checks whether a macro is not defined. If the identifier specified is not defined as a macro, the lines of code immediately follow the condition are passed on to the compiler. An identifier must follow the T#ifndefT keyword. The following example defines TMAX_LENT to be T50T if TEXTENDEDT is not defined for the preprocessor. Otherwise, TMAX_LENT is defined to be T75T.
#ifndef EXTENDED # define MAX_LEN 50 #else # define MAX_LEN 75 #endif
The #else directive
If the condition specified in the T#ifT, T#ifdefT, or T#ifndefT directive evaluates to T0T, and the conditional compilation directive contains a preprocessor T#elseT directive, the lines of code located between the preprocessor T#elseT directive and the preprocessor T#endifT directive is selected by the preprocessor to be passed on to the compiler.
The #endif directive
The preprocessor T#endifT directive ends the conditional compilation directive.
/** ** This example contains preprocessor ** conditional compilation directives. **/ #include <stdio.h> #define TEST 2 int main(void) { static int array[ ] = { 1, 2, 3, 4, 5 }; int i; for (i = 0; i <= 4; i++) { array[i] *= 2; #if TEST >= 1 printf("i = %d\n", i); printf("array[i] = %d\n", array[i]); #endif } return(0); }
O/p:
i = 0 array[i] = 2 i = 1 array[i] = 4 i = 2 array[i] = 6 i = 3 array[i] = 8 i = 4 array[i] = 10
Message generation directives includes the #error directive, which defines text for a compile-time error message.
The #error directive
A Tpreprocessor error directiveT causes the preprocessor to generate an error message and causes the compilation to fail. For example, the directive.
#define BUFFER_SIZE 255 #if BUFFER_SIZE < 256 #error "BUFFER_SIZE is too small." #endif
generates the error message:
BUFFER_SIZE is too small