C++ preprocessor


Preprocessors are instructions that instruct the compiler on the preprocessing that needs to be done before actual compilation.

All preprocessor directives begin with a pound sign (#), and only space characters can appear before preprocessor directives. Preprocessing directives are not C++ statements, so they do not end with a semicolon (;).

We have seen that there are #include directives in all previous examples. This macro is used to include header files into source files.

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

#define Preprocessing

#define preprocessing directive is used to create symbolic constants. This symbolic constant is usually called macro. The general form of the instruction is:

#define macro-name replacement-text

When this line of code appears in a file, all subsequent macros in the file will Replaced with 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’s test this code and see the results of preprocessing. Assuming that the source code file already exists, use the -E option to compile and redirect the results to test.p. Now, if you look at the test.p file, you will see that it already contains a lot of information, and the values ​​at the bottom of the file have been changed to the following:

$gcc -E test.cpp > test.p

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

    return 0;
}

Function 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 minimum is " << MIN(i, j) << endl;

    return 0;
}

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

The minimum is 30

Conditional compilation

There are several instructions that can be used to selectively compile part 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. Please look at the following preprocessor code:

#ifndef NULL
   #define NULL 0
#endif

You can only compile during debugging. The debugging switch can be implemented using a macro, as shown below:

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

If in the directive #ifdef DEBUG If the symbolic constant DEBUG has been defined before, the cerr statement in the program will be compiled. You can comment out a part of the program using #if 0 statement as shown below:

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

Let us try the following 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
   /* 这是注释部分 */
   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 will Produces the following results:

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

# and ## operators The

# and ## preprocessor operators are available in both C++ and ANSI/ISO C. The # operator converts the replacement-text token to a quoted string.

Please look at the macro definition below:

#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 will produce the following results:

HELLO C++

Let's see what it is How it works. It is not difficult to understand that the C++ preprocessor converts the following line:

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

into:

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

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

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

When CONCAT appears in a program, its arguments are concatenated and used in place of the macro. For example, CONCAT(HELLO, C++) in the program will be replaced by "HELLO C++", as shown in the example below.

#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 see how it works. It is not difficult to understand that the C++ preprocessor converts the following line:

cout << concat(x, y);

into:

cout << xy;

The predefined macros in C++

C++ provides the following table Some predefined macros:

MacroDescription
__LINE__This will Contains 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 contain a string of the form month/day/year, which represents the date when the source file was converted to target code.
__TIME__This will contain a string of the form hour:minute:second, which represents the time when the program was compiled.

Let’s look at an example of the above macros:

#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