乐创DIY C语言讲义​——2.2节

2.2 文件依赖关系和编译流程

C语言的源文件,包括.c文件和.h文件两种,一般地,我们把实现功能的函数,流程代码放在.c文件中,将一些变量的声明,类型定义的代码放在.h文件里面。在使用时,我们首先需要用“#include”预处理命令将.h文件包含进.c文件中才可以在.c文件中使用.h文件中定义的变量。

比如,某个程序员将所有加法相关函数写在了“add.c”和“add.h”这两个文件中。在C语言中实现某一个同样特定功能的代码,可以将其封装成一个函数,并且提供给其它代码反复使用。如在“add.c”文件中定义了一个十进制的加法函数“add_10();“,这是一个函数,如果想要它被其他源文件调用,那就要在相应的.h文件里面进行全局申明。另一个文件(假设main.c里面的主函数)要调用时,需要包含“add.h”这个文件,那此时这样的关系就是我们上文中的依赖关系。可以用如图2-2-1所示的树状关系来表示这个依赖关系。图2-2-1中,这里我们可以说目标文件的生成需要依赖main.c文件,而main.c文件需要依赖a.c和b.c文件。

图2-2-1 函数依赖关系

以上简单解释了一下依赖关系的概念,接下来还有一个比较重要的话题没有讨论,即C语言是怎样从一行行的英文字母编程可以被计算机执行的程序的?其实C语言的编译过程用语言讲出来很简单,四个过程:预处理,编译,汇编,连接。但是要详细去解释他,四本后书都写不完,有些国外的专业程序员大拿,耗尽一生光阴来研究这玩样。尽管这样,我们还是简单地一起学习个九牛一毛。

首先预处理,这个阶段编译器只是把程序源文件里面的预处理符号进行处理,并无编译性质的参与。简单地说,以后大家在看到C语言源文件里以“#”号开头的语句,都是预处理命令,这里先记一下,我们后续再来详细解说。

接着编译,编译的过程,大家一开始的理解肯定是这样的:把各个相关的.c文件像鸡蛋一样拍到某个容器中,然后把这一摊代码像打蛋器一样在碗里乱搅和,然后就生成了可执行文件了。这个认识误区,特别是一开始就从IDE入门编程的,永远都会存在。其实,编译过程是不会产生可执行文件的,也不是把所有.c文件都放在一起搅和。编译过程是对每个.c文件进行单独的预处理,然后进行编译,编译生成出来一种类似于汇编语言的代码,我们也可以用编译命令将.c文件的汇编语言形式展现出来,如图2-2-2所示。

图2-2-2c文件转汇编

汇编,汇编其实很好理解,就是编译生成的汇编语言代码通过汇编器,生成机器语言的过程。我们也可以用命令直接生成每个.c文件编译,汇编结束后的机器语言二进制代码。如图2-2-3,”hello.o”文件就是这个二进制机器语言。

图2-2-3编译后产生的目标文件

最后的链接步骤,就是将所有依赖的文件和C语言库生成的目标文件按照特定的地址排列打包成一个大的可执行文件。编译过程的简单示例如图2-2-4所示。

图2-2-4程序生成简明过程

+++++++++++相关书籍推荐+++++++++++++

推荐理由:程序界绰号“龙书”的编程书籍,详细地讨论了编译器设计的重要主题,包括词法分析、语法分析、语法指导分析、类型检查、运行环境、中间代码生成、代码生成、代码优化等。并在最后两章讨论了实现编译器的一些编程问题和几个编译器实例。Edward只是之前阅读过一次,但是如果对C语言痴迷的朋友,可以研究研究。

推荐指数:

(0)

相关推荐