C preprocessor
The C preprocessor is not part of the compiler, but it is a separate step in the compilation process. In a nutshell, C preprocessors are nothing more than text replacement tools that instruct the compiler to complete the required preprocessing before actual compilation. We will abbreviate C Preprocessor as CPP.
All preprocessor commands begin with a pound sign (#). It must be the first non-null character, and to enhance readability, preprocessor directives should start from the first column. All important preprocessor directives are listed below:
Directive | Description |
---|---|
#define | Define macro |
#include | Include a source code file |
#undef | Cancel the defined macro |
#ifdef | If the macro has been defined, return true |
#ifndef | If the macro is not defined, return true |
##if | If the given condition is true, compile the following code |
#else | ##Alternatives to if |
#elif | If the previous #if given condition is not true , if the current condition is true, compile the following code |
#endif | End an #if...#else conditional compilation block |
#error | When standard error is encountered, output an error message |
##pragma | Use the standardized method to issue special command to the compiler |
Preprocessor Example
Analyze the following example to understand the different directives.
#define MAX_ARRAY_LENGTH 20
This directive tells CPP to replace all MAX_ARRAY_LENGTH with 20. Use #define to define constants to enhance readability.
#include <stdio.h>#include "myheader.h"
These directives tell CPP to get stdio.h from the System Library and add the text to the current source file. The next line tells CPP to get myheader.h from the local directory and add the contents to the current source file.
#undef FILE_SIZE#define FILE_SIZE 42
This command tells CPP to cancel the defined FILE_SIZE and define it as 42.
#ifndef MESSAGE #define MESSAGE "You wish!"#endif
This directive tells CPP to define MESSAGE only if MESSAGE is not defined.
#ifdef DEBUG /* Your debugging statements here */#endif
This directive tells CPP to execute the processing statement if DEBUG is defined. This directive is useful if you pass the -DDEBUG switch to the gcc compiler at compile time. It defines DEBUG and you can turn debugging on or off at any time during compilation.
Predefined macros
ANSI C defines many macros. You can use these macros in programming, but you do not directly modify these predefined macros.
Macro | Description |
---|---|
__DATE__ | The current date, one starting with "MMM DD Character constant represented in YYYY" format. |
__TIME__ | The current time, a character constant expressed in the format of "HH:MM:SS". |
__FILE__ | This will contain the current file name, a string constant. |
__LINE__ | This will contain the current line number, a decimal constant. |
__STDC__ | Defined to 1 when the compiler compiles to the ANSI standard. |
Let's try the following example:
#include <stdio.h>main(){ printf("File :%s\n", __FILE__ ); printf("Date :%s\n", __DATE__ ); printf("Time :%s\n", __TIME__ ); printf("Line :%d\n", __LINE__ ); printf("ANSI :%d\n", __STDC__ );}
When the above code (in the file test.c) is compiled and executed, it produces the following results:
File :test.cDate :Jun 2 2012Time :03:36:24Line :8ANSI :1
Preprocessor operators
The C preprocessor provides the following operators to help you create macros:
Macro continuation operator (\)
A macro is usually written on a single line. But if the macro is too long to fit on a single line, use the macro continuation operator (\). For example:
#define message_for(a, b) \ printf(#a " and " #b ": We love you!\n")
String constantization operator (#)
In the macro definition, when a macro parameter needs to be converted into a string constant, the string constantization operation is used symbol(#). This operator used in a macro has a specific argument or argument 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 will produce the following results:
Carole and Debra: We love you!
Mark the paste operator (##)
within the macro definition The token paste operator (##) combines two arguments. It allows two independent tags to be combined into one tag in a macro definition. 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 this happens is because this instance produces the following actual output from the compiler :
printf ("token34 = %d", token34);
This example demonstrates that token##n will be connected to token34. Here, we use the string constant operator (#) and to mark the paste operation. symbol(##).
defined() operator
Preprocessordefined The operator is used in constant expressions to determine whether an identifier has been defined using #define Pass. The value is true (non-zero) if the specified identifier is defined. If the specified identifier is undefined, the value is false (zero). The following example demonstrates the use of the defined() operator:
#include <stdio.h>#if !defined (MESSAGE) #define MESSAGE "You wish!"#endifint main(void){ printf("Here is the message: %s\n", MESSAGE); return 0;}
When the above code is compiled and executed, it produces the following results:
Here is the message: You wish!
Parameterized macros
A powerful feature of CPP is the ability to use parameterized macros to simulate functions. For example, the following code calculates the square of a number:
int square(int x) { return x * x;}
We can rewrite the above code using macros, as follows:
#define square(x) ((x) * (x))
Before using a macro with parameters, you must use #define Command definition. The parameter list is enclosed in parentheses and must immediately follow the macro name. No spaces are allowed between the macro name and the opening 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 results:
Max between 20 and 10 is 20