程序翻译过程
前言
一天我突然忘了快速排序的代码实现,但我又没写笔记/博客,这时候我就开始后悔为什么当初没有写笔记、博客啊,于是我从现在每三天开始写一篇博客以便日后好复习。
我们写的源代码到可执行程序经历了哪些步骤?现在起我们开始一段代码的艺术之旅吧。
程序翻译过程
翻译过程 | gcc命令 | 说明 |
---|---|---|
预处理 | gcc -E test,c -o test,i | 宏替换,去注释,头文件展开,条件编译 |
编译 | gcc -S test.i -o test,s | 将c编译成汇编语言 |
汇编 | gcc -c test.s -o test,o | 将汇编语言翻译成二进制目标文件 |
链接 | gcc test.o -o my.exe | 生成可执行程序 |
这些命令看起有点复杂
怎么快速记忆这些gcc命令
-o的意思是给生成的文件重命名
★从预处理到汇编的 gcc 编译选项刚好是 ESc 键盘上的退出键
生成的文件后缀依次是 i,s,o 这个可以不用记 因为在Linux环境下并不关心 文件的后缀
后面我们编译程序的时候直接 gcc test.c -o test.exe或者 gcc -o test.exe test.c 一步到位
为什么是这个步骤?
机器只能识别二进制,为了书写方便才发明的汇编,因为汇编也不够方便,才发明的高级语言。当人们写汇编的时候,就需要先写二进制构成编译器来翻译汇编语言,但二进制的编译器维护不太方便,于是又有二进制的汇编编译器,写了一个汇编语言的汇编编译器,这称为编译器的自举
。同理汇编到高级语言也是这样,先有低一级语言写成的高一级的编译器。不管怎样,历史上都是 二进制->汇编->高级语言,虽然可以从高级语言直接到二进制但是代价很大,没有二进制直接到高级语言的编译器。所以我们的源代码是一步一步的翻译到二进制的。
验证预处理阶段
原本只有13行的源代码经过预处理后变为800多行就是因为头文件展开了
经过条件编译后 v1 v2 条件下的代码都被编译器裁掉了 验证了在预处理阶段会进行条件编译
链接的故事
什么叫链接呢?
链接就是把我们的程序和库结合的过程。
我们可以通过 vim/usr/include/stidio.h 来查看stdio.h这个头文件
我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
c标准库
ldd 可执行文件
可以看到所依赖的库
最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指
定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,
这样就能实现函数“printf”了,而这也就是链接的作用
Linux下默认安装好了c标准库,但在windows就没有
这个图就是我们以前在windows安装c标准库的过程
Linux下库分为两种,动态库和静态库
动态库和静态库
Linux:
动态库.so
静态库.a
咱们c 标准库就是动态库 libc.so.6 去掉前缀lib 后缀so.6 库名就是c
windos:
动态库.dll
以前我玩cf突然启动不了了,提示缺少.dll文件,我印象很深刻
静态库.lib
为什么要有链接
让开发站在巨人的肩膀上,提高开发效率
动态链接和静态链接
什么是动态链接和静态链接
简单来说
通过动态库的链接称为动态链接,通过静态库的链接称为静态库链接
具体我举个例子来说,小明要上高中了,但是想去上网,于是他就问学长哪里有黑网吧可以上网,学长说在学校的东门有一家网吧可以上网。于是小明周天安排上午学习,中午去上网,下午再完成作业。于是中午他就出校门去上网了。 这里学长相当于编译器,网吧相当于动态库,电脑相当于里面的方法,编译器告诉动态库的地址,程序执行到一定的过程就触发找对应的库了。还没上学期就知道网吧的地址了,也就是还没运行前就链接了。
共享动态库一但动态库丢失,所有动态链接的程序都无法执行了
编译器告诉动态库地址,程序去对应位置找称为动态链接
静态链接:
黑网吧被热心群众举报了,但是经过一年小明的努力,学习成绩是班上前几,于是他爸就给买了台笔记本安装在宿舍里。
在编译的时候,把库中的方法(电脑)拷贝(购买)到自己的静态库(宿舍电脑)中,自己的代码再和静态库链接这称为静态链接
这样不在关心任何的库,但是每次编译时都要拷贝方法到自己程序中,比较浪费资源
比如有十个程序都用到了printf 如果静态链接的话,printf就要加载十份到内存中
证明
- gcc默认形成的是动态链接通过file指令查看可执行程序的链接方式
2.静态链接编译后的程序更大
验证的时候我们编译的时候加上 -static 这个命令选项
可能有的同学可能运行不起,因为Linux 默认是没有安装静态库的
sudo yum install -y glibc-static
sudo yum install -y libstdc+±static
复制这两个语句就可以了 如果是管理员就不用加sudo
总结动态链接和静态链接的优缺点
动态链接 | 静态链接 | |
---|---|---|
优点 | 节省资源 | 浪费资源 |
缺点 | 动态库不能丢失 | 可以丢失 |
静态链接的应用场景
既然静态链接这么浪费资源,那我们什么时候使用静态链接呢?
因为静态链接不依赖任何的动态库,所以可移植性很强,在对跨平台有较高要求的场景下,静态链接还是有用武之地的