C++ 预处理

  • 预处理

    预处理程序是指令,它们向编译器提供指令,以在实际编译开始之前对信息进行预处理。所有预处理程序指令均以开头,并且一行上的预处理程序指令之前只能出现空格字符。预处理程序指令不是C++语句,因此它们不以分号(;)结尾。您已经在所有示例中看到了#include指令。该宏用于将头文件包含到源文件中。 C++支持许多预处理器指令,例如#include,#define,#if,#else,#line等。让我们看看重要的指令-
  • #define预处理程序

    #define预处理程序指令创建符号常量。符号常量称为,指令的一般形式为-
    
    #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;
    }
    
    尝试一下
    如果我们编译并运行以上代码,这将产生以下结果-
    
    The minimum is 30
    Trace: Inside main function
    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__ 它包含一个形式为hour:minute:second的字符串,即程序编译时的时间。
    让我们看一个上面所有宏的例子-
    
    #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