C++预处理
预处理器是指令,它的编译器预处理指令给出的信息,实际编译开始之前。
所有的预处理指令以#开头,只有空格字符可能线路上的预处理器指令之前出现。预处理指令不是C++语句,这样它们就不会以一个分号(;)结束。
已经看到所有的例子#include指令。这个宏用于包括头文件到源文件。
还有用C++的支持 如 #include, #define, #if, #else, #line,等预处理指令,让我们看看重要指令:
#define预处理:
#define预处理指令创建符号常量。符号常量为 amacro指令的一般形式是:
#define macro-name 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; }
函数宏:
可以使用的#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
条件编译:
有几个指令,可以用它来有选择地进行编译程序的部分源代码。这个过程被称为条件编译。
有条件的预处理器结构很像if选择结构。考虑下面的预处理器的代码:
#ifndef NULL #define NULL 0 #endif
可以用于调试目的编译一个程序,并且可以调试打开或关闭使用单个宏如下:
#ifdef DEBUG cerr <<"Variable x = " << x << endl; #endif
将导致在程序编译 cerr 声明如果符号常量DEBUG 指令在 #ifdef DEBUG之前被定义。可以使用 #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; }
如果我们编译并运行上面的代码,这会产生以下结果:
Trace: Inside main function The minimum is 30 Trace: Coming out of main function
#和##运算符:
#和##预处理器运算符是用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;
预定义的C++宏:
C++提供了许多下面提到的预定义宏:
宏 | 描述 |
---|---|
__LINE__ | 这包含程序的当前行号时,它被编译 |
__FILE__ | 这包括当它被编译的程序的当前文件名 |
__DATE__ | 这包含格式月/日/年,它是转换源文件到目标代码的日期的字符串 |
__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