C++ Preprocessor

Preprocessors are directives that instruct the compiler to perform preprocessing required before actual compilation.

All preprocessor directives begin with the hash sign (#). Only whitespace characters may appear before a preprocessor directive. Preprocessor directives are not C++ statements, so they do not end with a semicolon (;).

We have seen that in all previous examples,#includeDirective. This macro is used to include a header file into the source file.

C++ also supports many preprocessor directives, such as #include, #define, #if, #else, #line, etc. Let's take a look at these important directives.

#define Preprocessor

The #define preprocessor directive is used to create symbolic constants. This symbolic constant is often calledMacrothe general form of the directive is:

#define macro-name replacement-text 

When this line of code appears in a file, all subsequent occurrences of the macro in that file will be replaced by replacement-text before the program is compiled. For example:

#include <iostream> using namespace std; #define PI 3.14159 int main () { cout << "Value of PI :" << PI << endl; return 0; }

Now, let us test this code to see the result of preprocessing. Assuming the source code file already exists, next use the -E option to compile and redirect the result to test.p. Now, if you look at the test.p file, you will see that it already contains a large amount of information, and the value at the bottom of the file has been changed to the following:

$ gcc -E test.cpp > test.p

...
int main ()
{
 
    cout << "Value of PI :" << 3.14159 << endl; 

    return 0;
}

Parameterized Macro

You can use #define to define a macro with parameters, as follows:

#include <iostream> using namespace std; #define MIN(a,b) (a<b ? a : b) int main () { int i, j; i = 100; j = 30; cout <<"The smaller value is:" << MIN(i, j) << endl; return 0; }

When the above code is compiled and executed, it produces the following results:

较小的值为:30

Conditional Compilation

There are several directives that can be used to selectively compile parts of the program source code. This process is called conditional compilation.

The structure of the conditional preprocessor is very similar to the if selection structure. Take a look at the following preprocessor code:

#ifdef NULL
   #define NULL 0
#endif

You can compile only during debugging. The debug switch can be implemented with a macro, as follows:

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

If the symbolic constant DEBUG has been defined before the directive #ifdef DEBUG, then the statements in the programcerrstatements will be compiled. You can use the #if 0 statement to comment out a part of the program, as follows:

#if 0
   不进行编译的代码
#endif

Let's try the following example:

Example

#include <iostream> using namespace std; #define DEBUG #define MIN(a,b) (((a)<(b)) ? a : b) int main () { int i, j; i = 100; j = 30; #ifdef DEBUG cerr <<"Trace: Inside main function" << endl; #endif #if 0 /*This is the comment section*/ cout << MKSTR(HELLO C++) << endl; #endif cout <<"The minimum is " << MIN(i, j) << endl; #ifdef DEBUG cerr <<"Trace: Coming out of main function" << endl; #endif return 0; }

When the above code is compiled and executed, it produces the following results:

Trace: Inside main function
The minimum is 30
Trace: Coming out of main function

The # and ## operators

The # and ## preprocessor operators are available in both C++ and ANSI/ISO C. The # operator converts a replacement-text token into a string enclosed in quotation marks.

Consider the following macro definition:

Example

#include <iostream> using namespace std; #define MKSTR( x ) #x int main () { cout << MKSTR(HELLO C++) << endl; return 0; }

When the above code is compiled and executed, it produces the following results:

HELLO C++

Let's take a look at how it works. It is not hard to understand that the C++ preprocessor takes the following line:

cout << MKSTR(HELLO C++) << endl;

Converted to:

cout << "HELLO C++" << endl;

The ## operator is used to concatenate two tokens. Here is an example:

#define CONCAT( x, y )  x ## y

When CONCAT appears in the program, its arguments are concatenated and used to replace the macro. For example, CONCAT(HELLO, C++) in the program would be replaced with "HELLO C++", as shown in the example below.

Example

#include <iostream> using namespace std; #define concat(a, b) a ## b int main() { int xy = 100; cout << concat(x, y); return 0; }

When the above code is compiled and executed, it produces the following results:

100

Let's take a look at how it works. It is not hard to understand that the C++ preprocessor takes the following line:

cout << concat(x, y);

Converted to:

cout << xy;

Predefined macros in C++

C++ provides some predefined macros shown in the following table:

Macro Description
__LINE__ This will include the current line number when the program is compiled.
__FILE__ This will include the current file name when the program is compiled.
__DATE__ This will include a string in the form month/day/year, which represents the date when the source file is converted to object code.
__TIME__ This will include a string in the form hour:minute:second, which represents the time when the program was compiled.

Let's look at the examples of the above macros:

Example

#include <iostream> using namespace std; int main () { cout << "Value of __LINE__ : " << __LINE__ << endl; cout << "Value of __FILE__ : " << __FILE__ << endl; cout << "Value of __DATE__ : " << __DATE__ << endl; cout << "Value of __TIME__ : " << __TIME__ << endl; return 0; }

When the above code is compiled and executed, it produces the following results:

Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48
other extensions