Tutorial Study Image

C++ 预处理器


2023年6月13日, Learn eTutorial
754

C++ 的一个特殊方面是预处理器指令。它提供了其他高级语言无法提供的许多功能,程序员可以利用这些工具来构建高效、易读、易于编辑和可移植的 C++ 程序。

在 C++ 编译器编译 C++ 程序之前,编译器会先处理源代码。这种技术被称为预处理器,而操作被称为预处理。它是一种独立的程序部分,由 C++ 编译器在翻译的最初部分调用。此过程属于编译过程,但不是编译器的组成部分。它指示编译器在开始编译过程之前预处理数据。

由于这不是 C++ 中的语句,所有 C++ 预处理器指令都以 # 开头,并且不需要以分号 (;) 结尾。

通过 #define 指令创建一个符号常量,这些符号常量通常被称为宏。

其最一般的指令形式是


#define macro-name replacement-text
 

一个基本的 C++ 预处理指令程序


#include<iostream> 
#define val 100

using namespace std;

int main()
{
    cout << "Value will be :" << val << endl;
}

 

输出


Value will be :100

各种预处理器指令执行各种功能。这些预处理器指令分为以下几类

包含指令 宏定义指令 条件编译指令 其他指令

#include 

定义应包含的文件,特别是头文件。

·#define: 主要用于指定宏替换。

 

·#undef: 用于取消宏定义。

·#if: 它检查编译时条件。

 

·#endif: 它指示 #if 结束的位置。

 

·#ifdef: 用于测试宏定义。

·#ifndef: 如果宏未定义,则进行测试。

·#else: 当 #if 失败时,它提供替代选项。

· #error:

· #line: 为编译器消息提供行号。

·#pragma: 它提供由实现定义的编译器指令。

预处理器指令的四大主要类别是

  • 文件包含
  • 条件编译
  • 其他指令
  1. 在程序中,宏是代码的命名部分。当编译器遇到这个术语时,它会将名称替换为实际的代码片段。使用“#define”指令定义宏。现在让我们用一个程序来理解宏的定义

    使用宏的程序

    
    #include <iostream>
    
    // macro definition
    #define LIMIT 6
    int main()
    {
     for (int i = 0; i < LIMIT; i++) {
      std::cout << i << "\n";
     }
    
     return 0;
    }
    
     
    

    输出

    
    0
    1
    2
    3
    4
    5
    

    当编译器运行前面的程序时,它会将单词 LIMIT 替换为数字 6。在宏定义中,单词“LIMIT”被称为宏模板,而数字“6”是宏展开。

    宏定义不带分号 (;) 结束。宏定义不需要以分号结束。

    带参数的宏: 宏也接受参数。带参数定义的宏与函数共享类似的行为。让我们通过一个程序来检查这一点

    带参数宏的程序

    
    #include <iostream>
    
    // macro with parameter
    #define AREA(l, b) (l * b)
    int main()
    {
     int l1 = 20, l2 = 10, area;
    
     area = AREA(l1, l2);
    
     std::cout << "The area of rectangle is: " << area;
    
     return 0;
    }
    
     
    

    输出

    
    The  area of rectangle is: 200
    

    上面的程序演示了当编译器在程序中遇到表达式 AREA(l, b) 时,它会用语句 (l*b) 替换它。此外,提供给宏模板 AREA(l, b) 的值将在语句 (l*b) 中被替换。因此,AREA(20, 10) 将等于 20*10。

  2. 文件包含

    这种预处理器指令指示编译器将文件添加到程序的源代码中。用户可以向程序添加两种不同类型的文件

    标准文件与头文件: printf()scanf() 等预定义函数都在这些文件中定义。为了使这些函数工作,这些文件必须存在。各种函数在不同的头文件中声明。'iostream' 文件包含执行基本 I/O 的函数,而 'string' 文件包含处理字符串操作的函数。

    语法

    
    #include< file_name >
     
    

    其中文件名表示应包含的文件的名称。'<' 和 '>' 括号将告诉编译器在标准目录中查找文件。

    用户定义文件: 当程序变得太大而难以一次性使用时,将其分解为较小的文件是一个好主意。用户定义文件就是这类文件。您可以包含这些文件

    
    #include"filename"
     
    
  3. 条件编译

    条件编译指令是一种指令,可以根据某些标准编译或省略编译程序的指定部分。“ifdef”和“endif”是可用于执行此操作的两个预处理指令。

    语法

    
    #ifdef macro_name
        statement1;
        statement2;
        statement3;
        .
        .
        .
        statementN;
    #endif
     
    

    如果定义了名为“宏名称”的宏,则语句块将正常执行;但是,如果未声明,编译器将跳过此语句块。

  4. 其他指令

    除了上述两个指令之外,还有两个很少使用的指令。它们是

    #undef 指令: 可以使用 #undef 指令取消宏的定义。此命令的作用是

    
    #undef LIMIT
     
    

    如果使用此语句,现有宏 LIMIT 将未定义。在此之后,所有“#ifdef LIMIT”语句都将评估为 false。

    #pragma 指令: 此特殊用途指令旨在启用或禁用某些功能。这些指令是编译器特定的,这意味着它们在不同编译器之间有所不同。以下是一些 #pragma 指令

    • #pragma startup 和 #pragma exit: 使用指令 #pragma startup 和 #pragma exit,我们可以指示在程序启动之前(在控制权传递给 main() 之前)和程序退出之前(在控制权从 main() 返回之前)必须执行哪些函数。

      GCC 编译器与以下程序不兼容。

      
      #include <bits/stdc++.h>
      using namespace std;
       
      void func1();
      void func2();
      
      #pragma startup func1
      #pragma exit func2
      
      void func1()
      {
       cout << "Inside the func1()\n";
      }
      
      void func2()
      {
       cout << "Inside the func2()\n";
      }
      
      int main()
      {
       void func1();
       void func2();
       cout << "Inside the main()\n";
      
       return 0;
      }
      
       
      

      输出

      
      Inside the func1()
      Inside the main()
      Inside the func2()
      

      当由 GCC 编译器运行时,上述代码将导致以下输出

      在 main() 内部

      发生这种情况是因为 GCC 不支持 #pragma startup 或 exit。

    • #pragma warns 指令:此指令可用于隐藏编译期间显示的警告消息。