预处理器

在 C 编译器开始编译源代码文件之前,将在预处理阶段处理该文件。此阶段可以通过单独的程序完成,也可以完全集成在一个可执行文件中。无论如何,在编译正确开始之前,编译器会自动调用它。预处理阶段通过应用文本替换将你的源代码转换为另一个源代码或翻译单元。你可以将其视为已修改扩展的源代码。该扩展源可以作为文件系统中的真实文件存在,或者它可以仅在被进一步处理之前短时间存储在存储器中。

预处理程序命令以井号(“#”)开头。有几个预处理器命令; 其中两个最重要的是:

  1. 定义

    #define 主要用于定义常量。例如,

    #define BIGNUM 1000000
    int a = BIGNUM; 
    

    int a = 1000000;
    

    #define 以这种方式使用,以避免在源代码文件中的许多不同位置显式地写出一些常量值。这在以后需要更改常量值时非常重要; 在 #define 中,改变它的次数要小得多,而不是必须在分散在整个代码中的多个地方进行更改。

    因为 #define 只进行高级搜索和替换,所以你也可以声明宏。例如:

    #define ISTRUE(stm) do{stm = stm ? 1 : 0;}while(0)
    // in the function:
    a = x;
    ISTRUE(a);
    

    变为:

    // in the function:
    a = x;
    do {
        a = a ? 1 : 0;
    } while(0);
    

    在第一次近似时,此效果与内联函数大致相同,但预处理器不提供 #define 宏的类型检查。众所周知,这容易出错,使用时需要非常谨慎。

    另请注意,预处理器也会用空格替换注释,如下所述。

  2. 包括

    #include 用于访问源代码文件之外定义的函数定义。例如:

     #include <stdio.h> 
    

    导致预处理器在编译之前将 <stdio.h> 的内容粘贴到 #include 语句位置的源代码文件中。#include 几乎总是用于包含头文件,这些文件主要包含函数声明和 #define 语句。在这种情况下,我们使用 #include 以便能够使用 printfscanf 等函数,其声明位于文件 stdio.h 中。C 编译器不允许你使用函数,除非之前已在该文件中声明或定义; 因此,#include 语句是在 C 程序中重用先前编写的代码的方法。

  3. 逻辑运算

    #if defined A || defined B
    variable = another_variable + 1;
    #else
    variable = another_variable * 2;
    #endif
    

    将更改为:

    variable = another_variable + 1;
    

    如果之前在项目的某个地方定义了 A 或 B. 如果不是这种情况,预处理器当然会这样做:

    variable = another_variable * 2;
    

    这通常用于在不同系统上运行或在不同编译器上编译的代码。由于存在全局定义,即编译器/系统特定的,你可以在这些定义上进行测试,并始终让编译器只使用他将编译的代码。

  4. 评论

    预处理器用单个空格替换源文件中的所有注释。评论由//指示直到行的末尾,或者开放/*和结束*/评论括号的组合。