跳到主要内容

编译和链接详解-预处理

转自:旧友与酒

  • 预处理命令是在编译之前对源代码进行预处理的指令,它们通常以井号(#)开头。这些命令对源代码进行各种处理,如宏定义、文件包含、条件编译等。以下是一些常用的预处理命令:

  • 宏定义 #define、条件编译 #if, #ifdef, #ifndef, #else, #elif, #endif、宏展开 #undef、字符串化 #、连接 ##

  • 文件包含 (#include):用于将另一个文件的内容包含到当前文件中。

  • 警告指令 (#warning):编译时产生警告信息(语法形式:#warning message)。

  • 错误指令 (#error):编译时产生错误信息(语法:#error标记-字符串,此指令发出的错误消息包含 token-string 参数。token-string 参数不受宏扩展的约束。此指令在预处理过程中最有用,用于通知开发人员程序不一致或违反约束。)。

  • 行控制 (#line):更改行号和文件名。(语法:#line digit-sequence ["filename"],预处理器将编译器的行号和文件名报告值设置为给定行号和文件名。编译器使用行号和可选文件名来引用它在编译过程中找到的错误。行号通常引用当前输入行,文件名引用当前输入文件。各行在经过处理后,行号将递增。)

    #include "stdio.h"
    int main(void){
    printf("-- %s: %d -- \n", __FILE__, __LINE__);
    #line 201 "main.c"
    printf("-- %s: %d -- \n", __FILE__, __LINE__);
    #line 101 "main.c"
    printf("-- %s: %d -- \n", __FILE__, __LINE__);
    printf("-- %s: %d -- \n", __FILE__, __LINE__);
    #line 110 "main.c"
    printf("-- ------------\n");
    printf("-- %s: %d -- \n", __FILE__, __LINE__);
    return 0;
    }

Image

  • 版本控制 (#pragma):编译器特定的指令,用于控制编译器行为。具体指令可以参考:Pragma 指令与 __pragma 和 _Pragma 关键字 | Microsoft Learn;

  • 这些预处理命令在C语言中非常重要,它们允许程序员在编译阶段进行代码的定制和条件编译,从而提高代码的可读性、可维护性和灵活性。然而,不同的编译器可能会提供一些特定的、非标准的预处理指令或对标准指令提供扩展

123

  • 预处理作为编译过程的第一个阶段,它主要完成以下内容:删除注释、宏展开、文件包含(如果包含的是系统头文件(尖括号<>),预处理器会在标准系统目录中搜索;如果是本地头文件(双引号""),则在用户指定的目录中搜索。)、条件编译、行控制、错误和警告(以便编译时产生调试用的行号及编译错误警告行号。)、字符串化、标记粘贴等。总的来说,预处理就是对预处理指令的一个处理过程。
  • 完成以上操作后会输出预处理后文件:预处理的结果通常生成一个 .i 文件,这个文件包含了原始源代码经过上述步骤处理后的内容。不过,这个文件不是必须的,因为编译器可以直接将预处理的结果传递给编译阶段。编译器将开始实际的编译过程,将源代码转换成机器代码或中间表示形式。