Cplusplus 简明教程

C++ Preprocessor

预处理器是指令,可在实际编译开始之前向编译器提供对信息进行预处理的指令。

所有预处理器指令都以 # 开头,并且在一行的预处理器指令之前只能出现空白字符。预处理器指令不是 C++ 语句,因此它们不会以分号 (;) 结束。

您已在所有示例中都看到了 #include 指令。此宏用于将头文件包含到源文件中。

C++ 支持多种预处理器指令,例如 #include、#define、#if、#else、#line 等。让我们看看重要的指令 −

The

#define 预处理器指令创建符号常量。符号常量称为 macro ,指令的一般形式为 −

#define macro-name replacement-text

当此行出现在某个文件中时,在程序编译之前,该文件中宏的所有后续出现都会被 replacement-text 替换。例如 −

#include <iostream>
using namespace std;

#define PI 3.14159

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

   return 0;
}

现在,让我们对这段代码进行预处理,以查看结果(假设我们有源代码文件)。因此,让我们使用 -E 选项对其进行编译,并将结果重定向到 test.p。现在,如果您检查 test.p,它将包含大量信息,并且在底部,您会发现已将值替换为以下内容 −

$gcc -E test.cpp > test.p

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

Function-Like Macros

您可以使用 #define 来定义一个作为参数的宏,如下所示 −

#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;
}

如果我们编译并运行上述代码,这将产生以下结果:

The minimum is 30

Conditional Compilation

可以使用多个指令来编译程序源代码的某些部分。此过程称为条件编译。

条件预处理结构非常像“if”选择结构。考虑以下预处理器代码 −

#ifndef NULL
   #define NULL 0
#endif

您可以出于调试目的编译程序。您还可以使用以下单个宏打开或关闭调试 −

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

如果在指令 #ifdef DEBUG 之前已定义了符号常量 DEBUG,则会导致 cerr 语句在程序中被编译。可以使用 #if 0 语句对程序的部分进行注释,如下所示 −

#if 0
   code prevented from compiling
#endif

我们尝试以下示例 −

#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 commented part */
   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;
}

如果我们编译并运行上述代码,这将产生以下结果:

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

The

# 预处理器运算符可在 C++ 和 ANSI/ISO C 中使用。 运算符会导致替换文本标记被转换为一个字符串(由引号包围)。

考虑以下宏定义 −

#include <iostream>
using namespace std;

#define MKSTR( x ) #x

int main () {

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

   return 0;
}

如果我们编译并运行上述代码,这将产生以下结果:

HELLO C++

我们来看看它如何工作的。很容易理解,C++ 预处理器会转换 −

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

上述行将被转换成以下行 −

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

运算符用于连接两个标记。这里有一个示例 −

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

当 CONCAT 出现在程序中时,它的自变量是连接起来的,并且用于替换宏。例如,在程序中,CONCAT(HELLO, C) 被替换为“HELLO C”,如下所示。

#include <iostream>
using namespace std;

#define concat(a, b) a ## b
int main() {
   int xy = 100;

   cout << concat(x, y);
   return 0;
}

如果我们编译并运行上述代码,这将产生以下结果:

100

我们来看看它是如何工作的。很容易理解,C++ 预处理器会变换 −

cout << concat(x, y);

上述行将被转换成本行 −

cout << xy;

Predefined C++ Macros

C++ 提供了许多预定义的宏,如下所示 −

Sr.No

Macro & Description

1

LINE 这包含程序在被编译时的当前行号。

2

FILE 这包含程序在被编译时的当前文件名。

3

DATE 这包含一个形式为月/日/年的字符串,它是源文件转换为对象代码时的日期。

4

TIME 这包含一个形式为时:分:秒的字符串,它是程序被编译的时间。

我们来看一下上述所有宏的一个示例 −

#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;
}

如果我们编译并运行上述代码,这将产生以下结果:

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