Skip to content

预处理器

1. 什么是预处理器

预处理器是 编译过程中一个单独的步骤

预处理在编译之前进行,预处理之后的文件将会被输出给编译器

2. 预处理指令

2.1 替换文本宏

  1. 仿对象宏:#define 标识符 替换列表 将之后每一个出现的标识符替换成替换列表(替换列表可以为空),示例:

    c
    #include <stdio.h>
    
    #define NUM 100
    
    int main(void){
        printf("%d", NUM);
    }

    程序将会输出 100

  2. 仿函数宏:

    1. #define 标识符(形参列表) 替换列表 当下文出现标识符紧跟一个”实参列表“的文本,将会被替换成 替换列表,同时 替换列表 中与形参列表中的形参相同的文本将会被替换成”实参列表“中对应的实参 示例:

      c
      #define max(a,b) (((a)>(b))?(a):(b))
      
      int main(void){
          printf("%d",max(1,2));
      }

      max(1,2) 会被替换成 (((1)>(2))?(1):(2))
      因为宏是文本的替换,因此在替换过程中可能会导致一些运算符优先级问题,如下:

      c
      #define F(x) x+2
      #define G(x) 3*x
      
      int main(void){
          printf("%d", G(F(2)));
      }

      此时 G(F(2)) 被替换成 3*F(2)F(2) 被替换成 2+2,因此 G(F(2)) 会被替换成 3*2+2!可能会造成与预期不同的结果,造成程序的错误。 因此,解决方案是把宏以及宏里面所有形参加括号:

      c
      #define F(x) ((x)+2)
      #define G(x) (3*(x))
    2. #define 标识符(形参列表, ...) 替换列表 在替换列表中,额外实参会替换 __VA_ARGS__标识符 替换列表中可以包含标记序列 __VA_OPT__(内容):当没有额外实参的时候,标记序列被替换为空,否则被替换为 内容

      示例:

      c
      #define DEFINE_ARRAY(type, name, size, ...) type name[size] __VA_OPT__(= { __VA_ARGS__ })
      
      int main(void){
          DEFINE_ARRAY(int, arr, 4, 1, 2, 3, 4);
      }

      DEFINE_ARRAY(int, arr, 4, 1, 2, 3, 4) 会被替换成 int arr[4] = {1, 2, 3, 4}

    3. # 运算符:把实参包含在引号中,变成一个字符串字面量:

      示例:

      c
      #define STR(a) #a
      
      int main(void){
          printf("%s is %s", STR(mdr), STR("cute"));
      }

      STR(mdr) 会被替换成 "mdr"

      STR("cute") 会被替换成 "\"cute\""

    4. ## 运算符:连接两个记号

      示例:

      c
      #define FUN(x) int fun_##x(){return x;}
      
      FUN(2)
      
      int main(void){
          printf("%d", fun_2());
      }

      FUN(2) 会被展开成 int fun_2(){return 2;}

    5. #define 的替换列表包含多行内容时,在每一行(除了最后一行末尾加\

    示例:

    c
    #define FUN(x) int fun_##x(){return x;}
    #define OUTPUT(str, ...) printf(#str __VA_OPT__(,) __VA_ARGS__)
    #include<stdio.h>
    FUN(2)
    int main(void){
        OUTPUT(%d, fun_2());
    }

    展开后的结果:

    c
    #include<stdio.h>
    int fun_2(){return 2;}
    int main(void){
        printf("%d", fun_2());
    }

    程序会输出2

  3. #undef 标识符:解除之前对 标识符 的定义

  4. 不能 实现真正的递归或者重载

2.2 包含文件

  1. include "文件名"
  2. include <文件名>

(1)先搜索当前目录,搜索不到再搜索标准包含目录 (2)直接搜索标准包含目录

2.3 有条件编译

  1. defined 运算符

    defined 标识符:如果定义了 标识符,求值为 1,否则为 0

  2. #if#elif#else#endif

  3. #elifdef#elifndef

本章内容对应 cppref 链接如下: