【问题标题】:What happens when preprocessor lines are processed by the preprocessor? - the '.i' file当预处理器行由预处理器处理时会发生什么? - '.i' 文件
【发布时间】:2017-01-30 09:43:09
【问题描述】:

我正在使用 Gcc 的 Gnu cc 编译器 来编译我的 C 程序。考虑一个程序,

#include <stdio.h>
int main(){
  return 0;
}

现在,当我预处理上述代码时,使用

cpp sample.c > sample.i

sample.i 中有很多我没有包含的内容。比如说,“stdio.h”文件是预处理过的。如果是这样的话,

问题 1:

为什么我的预处理文件中有这么多行?我没有使用任何标准库函数或宏。

问题 2:

谁能解释一下当预处理器处理 C 文件时到底发生了什么?(我在“*.i”文件中得到的内容)

编译器:gcc

操作系统:Ubuntu

谢谢

【问题讨论】:

  • 它会直接打开包含文件,并就地复制内容。如果&lt;stdio.h&gt; 还有#includes 一些其他文件,这些文件也会被复制进来,依此类推。这就是为什么你会得到这么多你认为自己不想要的东西。

标签: c gcc c-preprocessor


【解决方案1】:

为什么我的预处理文件中有这么多行?我没有使用任何标准库函数或宏。

预处理只是编译过程的一部分。它或多或少是一个简单的文本替换,在预处理阶段不涉及更复杂的内容。预处理器不知道也不关心您是否在代码程序中使用了任何标准函数。优化器(作为编译过程的一部分)可能 “删除”不需要的部分。但是预处理器不这样做。 它将对您包含的所有头文件以及通过您的头文件包含的其他头文件等进行预处理。

谁能解释一下当预处理器处理 C 文件时究竟发生了什么?(我在“*.i”文件中得到的内容)

预处理涉及很多任务:宏替换、条件编译、字符串化、字符串连接等。 你可以在这里阅读更多关于cpp的详细信息:https://gcc.gnu.org/onlinedocs/cpp/

【讨论】:

    【解决方案2】:

    预处理器命令#include "aFile.h" 会将来自aFile.h 的漏洞内容放入您的cpp 文件中。这正是预处理器指令所在的地方。这就是您可以使用aFile.h 中定义的函数的原因。

    如果您有兴趣了解有关预处理器的更多信息,cplusplus.com 上有一个非常好的(和简短的)指导

    【讨论】:

    • 为什么要复制 stdio.h 文件的内容,而我没有使用任何与之相关的东西(没有库函数或宏)?
    • 预处理器不关心。
    • 你还没有使用它,但你可以。如果不需要它们,可以删除 include 语句。
    • @PantherCoder 预处理器不解析你的代码。它只关心指令和宏替换。即使尝试过,它也无法删除未使用的声明。
    【解决方案3】:

    预处理器进行文本替换。 #include &lt;stdio.h&gt; 的实际效果是将#include &lt;stdio.h&gt; 行替换为&lt;stdio.h&gt; 的内容。

    实际上,&lt;stdio.h&gt; 包含多个函数声明(例如 fprintf()、fscanf())、变量声明(例如 stdout、stdin)和一些宏定义(稍后使用时)代码,导致文本替换)。

    预处理器被指定为编译的一个阶段,它将源代码作为输入,根据需要替换文本(例如我描述的#include,宏扩展等),并输出结果源代码。该输出是您指向 sample.i 的输出。

    预处理器的输出然后输入到编译的后期阶段,它实际上理解声明、定义、语句等。

    编译的阶段是连续的——它们一个接一个地发生,而不是同时发生。因此,编译的后期阶段不会将任何信息反馈给预处理器。检测是否使用声明等是编译的后期阶段。但是,由于它不能将这些信息反馈给预处理器(并且预处理器是一个无知的程序,无论如何也不能使用这些信息),所以预处理器无法知道声明未被使用,并将它们过滤掉。

    【讨论】:

      【解决方案4】:

      1) 您可能不会使用它们,但您已将它们包含在第 1 行中

      #include <stdio.h>
      

      这就是你看到的东西的来源。尝试将其删除以查看差异。

      2) 预处理器读取您的 C 文件并处理您声明的所有预处理器指令。所有预处理器指令都以“#”符号开头。 '#include' 将用给定文件的内容替换这一行。您还有经典的“#ifndef”和“#define”指令。后者等于 'if' 语句,它允许您仅在定义符号时激活代码的一部分

      #ifndef _SOME_SYMBOL_
      #define _SOME_SYMBOL_
      
      #ifndef WIN32
       #include <some_file.h>
      #else
       #include <some_other_file.h>
      #endif
      
      int main() { return 0;}
      
      #endif //endof _SOME_SYMBOL_
      
      #ifndef _SOME_SYMBOL_ 
      #define _SOME_SYMBOL_
      
      // this second function is ignored
      int main() { return 0;}
      
      #endif //endof _SOME_SYMBOL_
      

      预处理器读取上述文件时,符号“_SOME_SYMBOL_”是未知的,所以预处理器对其进行初始化。接下来它包含文件,无论它是否知道WIN32。通常这种符号是通过命令行传递的。因此,您的部分代码是动态激活或停用的。

      预处理器会输出这个

      void some_other_function_from_some_other_file(){}
      
      int main() { return 0;}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-12-02
        • 2015-07-31
        • 2012-03-11
        • 1970-01-01
        • 2023-03-18
        • 2019-06-22
        • 1970-01-01
        相关资源
        最近更新 更多