我正在使用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
感谢
为什么我的预处理文件中有这么多行?我没有使用任何标准的库函数,也没有使用宏。
预处理只是编译过程的一部分。它或多或少是一个简单的文本替换,在预处理阶段不涉及更复杂的内容。预处理器不知道或不关心您是否在代码程序中使用了任何标准函数。优化器(作为编译过程的一部分)可能"移除"不需要的零件。但预处理器并不能做到这一点。它将对您包含的所有头文件以及通过头文件包含的其他头文件进行预处理,等等
有人能解释预处理器处理C文件时到底发生了什么吗。(我在'*.I'文件中得到的内容)
预处理涉及相当多的任务:宏替换、条件编译、字符串化、字符串连接等。您可以在此处详细阅读cpp
:https://gcc.gnu.org/onlinedocs/cpp/
预处理器命令#include "aFile.h"
将把aFile.h
中的孔内容放入cpp文件中。这正是预处理器指令所在的位置。这就是您可以使用aFile.h
中定义的函数的原因。
如果你有兴趣了解更多关于预处理器的信息,cplusplus.com上有一个非常好的(简短的)指南
预处理器执行文本替换。#include <stdio.h>
的净效果是用<stdio.h>
的内容替换#include <stdio.h>
行。
实际上,<stdio.h>
包含各种函数的几个声明(例如fprintf()
、fscanf()
)、变量的声明(例如,stdout
、stdin
)和一些宏定义(在以后的代码中使用时,会导致文本替换)。
预处理器被指定为编译的一个阶段,它将源代码作为输入,根据需要替换文本(例如,我所描述的#include
、宏扩展等),并输出生成的源代码。这个输出就是你引导到样本中的。i
然后,预处理器的输出被输入到编译的后期,后者实际上理解声明、定义、语句等。
编译的各个阶段是连续的——它们一个接一个地发生,而不是一次发生。因此,编译的后期不会向预处理器反馈任何信息。是编译的后期阶段检测是否使用了声明等。但是,由于它无法将这些信息反馈给预处理器(而且预处理器是一个无知的程序,无论如何都无法使用这些信息),预处理器无法知道声明是未使用的,并将其过滤掉。
1)您可能不使用它们,但您已将它们包含在第1行中
#include <stdio.h>
这就是你看到的东西的来源。尝试将其删除以查看差异。
2) 预处理器读取您的C文件并处理您声明的所有预处理器指令。所有预处理器指令都以"#"符号开头。"#include"将用给定文件的内容替换此行。您还有经典的"#ifndef"one_answers"#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;}