1.预处理阶段(-E)
指令 gcc -E test.c -o mytest.i
E代表预处理阶段,i代表预处理以后的文件格式
1,去注释,条件编译,宏替换,展开头文件
可以看到,展开了头文件,条件编译结束,宏替换掉
2.编译
编译阶段主要做以下工作
将c语言代码转换成机器识别的汇编语言
指令:gcc -S mytest.i -o mytest.s
S代表编译阶段,s代表转换的格式
转换以后的结果:
可以看到,都转成了汇编代码
3.汇编
将汇编语言翻译成目标文件
指令:gcc -c mytest.i -o mytest.o
转成二进制的目标文件
4.链接
目标文件无法执行,目标文件只有函数的调用,没有函数的实现,
链接的本质就是将自己的调用过程与实现过程链接起来
生成可执行文件
动态静态库
通过ldd我们可以看到当前代码所使用的的库是动态库还是静态库,常用来解决程式因缺少某个库文件而不能运行的一些问题。
比如我们当前所使用的的mytest文件,通过ldd得出使用的是动态库
也可以在编译过程中指定库,比如指定静态库
可以看到是使用静态库链接的
为什么要有库的概念呢?
存在c库。c++库,库是为了减少开发的工作量,就比如,map,如果我们实现一个,可能就得一两百行代码,但当我们封装成库以后,就不用再去写,直接调用就ok,是软件分工的一种表现。
库有动态库(.so)和静态库(.a)
程序通过调用库极大减少工作量。
静态库和动态库的优缺点:
静态链接优点(.a):不依赖第三方库,程序的可移植性差
缺点:浪费空间
动态链接优点:节省空间,二进制文件小。加载速度快
缺点:依赖动态库,可移植性差
依赖关系详解
程序在运行时需要经过以上几个阶段,但在实际运行中,需要多个文件(.h .cpp)共同编译,执行,但在linux下,无法有vs这种集群式开发软件,所以需要程序的依赖关系来解决这个问题,
就如以下代码一样
通过实际的依赖关系,就可以实现程序的声明,定义和调用
通过编译后,就可以看到有多个文件生成,再通过输出,即可让程序运行
再通过make clean
就可以清楚生成的解决方案。
其中clean称为伪函数,只实现删除解决方案的函数。