【Linux】Linux下的gcc/g++编译器与动静态库
目录
- 对程序的认知&&初识gcc
- 逐步分析程序的编译步骤
- 预编译【进行宏替换】
- gcc需要执行的指令 ⭐
- 编译【C语言——>汇编语言】
- gcc要执行的指令⭐
- 汇编【汇编语言——>可重定位目标二进制文件】
- gcc需要执行的指令
- 链接【生成可执行文件或库文件】
- gcc需要执行的指令 ⭐
- 巧记gcc命令选项与生成文件后缀【⭐】
- gcc与g++的区别
- 通过链接过程,理解动静态库
- 库的初步认识
- 动态库与静态库
- 动静态库的感性理解
- 动态链接和静态链接的区别
- end
对程序的认知&&初识gcc
- 对于一个程序来说,要经过编辑,编译,链接,运行四个阶段才能真正生成一个程序
那么如何使用gcc这个编译器呢?
格式 gcc [选项] 要编译的文件 [选项] [目标文件]
逐步分析程序的编译步骤
预编译【进行宏替换】
- 头文件的展开 —— 编译器第一件做的事
- 宏定义的替换
- 去注释
- 条件编译的执行
gcc需要执行的指令 ⭐
gcc -E file.c -o file.i
- -E 表示让gcc在预处理后停止编译过程
- -o,后面永远跟着编译后要生成的目标文件
- .c结尾的表示文件源程序,.i结尾的表示已经经过预处理的C与程序
编译【C语言——>汇编语言】
在编译阶段会执行以下四件事
- 语法分析
- 词法分析
- 语义分析
- 符号汇总
以上其实就是在将C语言的代码转化为汇编代码的一个流程
gcc要执行的指令⭐
gcc -S file.i -o file.s
- -S表示在编译结束后停止,不再进行汇编
- -o和前面一样,后面跟着希望生成的目标文件
- .s结尾的表示编译后生成的汇编文件
汇编【汇编语言——>可重定位目标二进制文件】
-
在汇编阶段会执行以下两件事
-
将汇编指令转换为二进制指令【需要特定的文本阅读器readelf】
-
形成符号表
gcc需要执行的指令
gcc -c file.s -o file.o
- -c表示gcc编译到目标代码
- .s结尾的表示经过编译后的汇编代码,.o结尾的表示汇编后的二进制代码
-
在汇编这一块,就是将汇编语言翻译成可以重定位的二进制文件,里面的二进制代码我们人眼是看不到的,要特定的阅读器才可以看得明白
-
有几个源文件【.c】就会生成几个目标文件【.o】
链接【生成可执行文件或库文件】
- 在链接阶段会执行以下两件事
- 合并段表
- 符号表的合并和重定位
gcc需要执行的指令 ⭐
gcc file.o -o mytest
’
巧记gcc命令选项与生成文件后缀【⭐】
- 命令选项:-E -S -c 【键盘左上角的Esc,不过中间的S要大写】
- 文件后缀:.i .s .o 【.iso为镜像文件的后缀,ISO也为国际标准化组织】
gcc与g++的区别
看了这么久gcc,我们来看看g++,其实这两个编译器的用法是一模一样的,只是对于gcc才说是用来编译C语言代码,对于g++来说是用来编译C++的代码
- 不过这只是笼统的说法,其实对于gcc而言也是可以编译C++代码的,对于g++而言是可以编译C语言代码的
通过链接过程,理解动静态库
库的初步认识
- 首先提出一个问题:为啥我们能在Linux下直接编写和编译C语言程序呢?
- 因为:Linux系统默认已经携带了语言级别的头文件和语言对应的库!
- 可以先来看看系统中的头文件所在目录,然后就可以看到我们熟悉的stdio.h、stdlib.h等等
- 像printf和scanf这些函数就是在头文件stdio.h实现的,因为头文件里面实现了这两个函数,所以我们才可以使用pinrf和scanf函数
其实我们在安装VS2019、VS2022的时候。最重要的一个工作是什么呢?其实在这么几十分钟的安装时间里,这个自动化程序更多的是在帮我们下载并安装语言的头文件和库文件【编译需要的两个东西】
动态库与静态库
-
Linux下:以lib作为前缀,.so作为后缀【libXXXXXX.so】
-
Windows下:以.dll作为后缀
- -
-Linux下:以lib作为前缀,.a作为后缀【libXXXXXX.so】
-
Windows下:以.lib作为后缀
动静态库的感性理解
接下来我们通过一个故事来讲解动态库和静态库
- 你呢上初中了,你的成绩还不错,处于中上游的水平,但是你网瘾有点大,必须要学习完后打游戏才能安心学习,如果只学习不打游戏,你是无法学习的。这时候你找到你的初中学长,学长学校附近有没有网咖呀,我想学习之余去打一会游戏,学长就说,北门出去转弯有一个小蚂蚁网咖,可以去哪里
- 就这样到了周末,你在上午完成了语文作业和数学作业,中午吃完饭后,你想去玩游戏,这时候你就想起学长说的那家小蚂蚁网咖,你就偷偷从北门溜出去玩了,准备下午回来再写英语和历史作业。此时呢就看到你学长和你说的 #小蚂蚁网吧🐜#,于是就进去找到网管,网管给你分配了一个座位,3块钱一个小时,你买了两个小时,然后就开始自己疯狂的游戏
1.我们可以把写数学和语文作业当成执行程序中的顺序语句和循环语句和判断语句和算法等序列,你执行到无法在直接在程序里指向的语句,如调用函数,去需要去动态库里去调用(小蚂蚁网咖
2为什么呢?就相当于是 我们在写代码的时候可能有一段逻辑写不下了,因为这段逻辑很复杂。但是要是实现这个逻辑刚好有这个库函数,所以你就去会调用这个库函数。这个库函数就相当于是网吧)
3.但是你怎么知道这个库函数在哪里的呢?——>你学长告诉你的呗。也就相当于你知道了库函数中这个函数的地址在哪里,你只需要顺着北门然后根据这个地址找过去就可以了
那这么来说你的学长就相当于是一个链接器,网吧就是一个动态库,你知道了动态库中所需要的这个函数的地址,然后你就顺藤摸瓜🍈地找到了这个地方,你的学长就做了一个链接的功能
接下来就是你上网的过程就是调用动态库中库函数的过程,那么打完后动态库的库函数也调用完了
- 但是事情完了嘛,当然没有,才刚刚开始。。。
- 你们学校呢也有很多同学喜欢玩游戏,也通过他们各自的学长知道了这个【小蚂蚁网吧】,于是周末也来玩,但是呢这个网吧似乎不太安全,突然警察👮造访,说他们涉嫌非法经营🈲,然后这个网吧就被封了,你和你的同校同学都玩不了,知道默默回学校
- 所以我们看到这个是共享的,但是动态库一旦不能使用了,那么我们再想去使用里面的库函数就不可能了,那么怎么办呢?
- 这时候期末考试了,你的成绩下滑了很多,这时候你的父亲来问你,你这么回事,成绩下滑这么多,这时候你就抱怨,学校一天就只让我们学习,之前哪里还有小蚂蚁网咖可以玩游戏,但是现在没有了,我如果只学习没有游戏打,我就效率很低。
- 这时候你的父亲就说,好没问题,我给你买一台电脑给你玩,但是你要保证你必须把成绩回上来。
- 这时候开学了,你就高高兴兴把你父亲给你的电脑抱在学校宿舍里面去了。这时候你打开电脑一看,
这个电脑不就是之前你在小蚂蚁网咖里面玩的那台吗,一问父亲才知道,他就是在小蚂蚁网咖老板哪里专门去买的。这下爽了,鼠标和键盘都不需要重新熟悉。
1.可以看到,其实对于从网吧中拿来的电脑,就是库中的那个函数,也就是将库中的整个函数直接放到你的程序中来,这样你完全不需要再到库中去调用函数了,直接在你的程序中使用即可
2.当你的同学去到黑网吧,然后得知被封了之后无奈返回后,这个时候你有这自己的电脑,完全不需要再去考虑是否有电脑可用的安全性了,但就是这个电脑放在宿舍可能有些占位子,原本比较宽阔的空间就要被一台电脑给霸占了,那确实是没办法
动态链接和静态链接的区别
接下去我们对【动态库】和【静态库】做一个分析梳理,更好地理解动静态库的原理
- ✔【动态链接】 —— 仅仅是把库中的你所用的方法的地址调用方法到程序里 网吧
- ✔【动态链接】 —— 仅仅是把库中的你所用的方法的地址调用方法到程序里 网吧
- 动态库缺点:我们的程序还是依赖任何库,一旦动态库缺失,我们的程序便无法运行
1.可以联想到,大家只要通过学长知道小蚂蚁网咖的地址,就都可以去玩里面的电脑。只需要知道网吧的地址在哪里,然后直接去即可,也就和函数一样直接进行一个调用,对自己的程序而言不需要消耗任何的空间
2.但是一旦网咖被封,那就无法通过这个地址再去玩里面的电脑了。也就是动态库丢失了,那此时我们再去调用库中的函数就会失败,这是动态库比较致命的一点
【静态链接】 —— 自己代码当中用到的库中的方法把函数实现直接拷贝到程序里
- 静态库优点:我们的程序不依赖任何库,自己就可以独立运行
- 静态库缺点:因为自身的拷贝问题比较浪费空间
1.对于静态库来说,确实是比较方便,不需要再去库里面调函数了,直接把这个函数整体拷贝到我们的程序中即可。也就是我们不需要依赖任何的库,也不用去大象网吧🐘
2.但是呢我们的程序也会变得非常庞大。我们是把函数的实现代码都放在我们的程序中,这需要大量的内存空间
end
感性大家的阅读,希望对大家有帮助,谢谢