开发工具:gcc/c++
1.背景知识
-o后面就是跟的要形成的程序
- 预处理(进⾏宏替换/去注释/条件编译/头⽂件展开等)
- 编译(⽣成汇编)
- 汇编(⽣成机器可识别代码)
- 连接(⽣成可执⾏⽂件或库⽂件)
- 可以记为 ESc iso
gcc编译选项
格式 gcc [选项] 要编译的⽂件 [选项] [⽬标⽂件]
预处理(进⾏宏替换)
1.预处理
• 预处理功能主要包括宏定义,⽂件包含,条件编译,去注释等。
• 预处理指令是以#号开头的代码⾏。
• 实例: gcc –E hello.c –o hello.i
• 选项“-E”,该选项的作⽤是让 gcc 在预处理结束后停⽌编译过程。
• 选项“-o”是指⽬标⽂件,“.i”⽂件为已经过预处理的C原始程序。
2 编译(⽣成汇编)
• 在这个阶段中,gcc ⾸先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的⼯作,
在检查⽆误后,gcc 把代码翻译成汇编语⾔。
• ⽤⼾可以使⽤“-S”选项来进⾏查看,该选项只进⾏编译⽽不进⾏汇编,⽣成汇编代码。
• 实例: gcc –S hello.i –o hello.s
3 汇编(⽣成机器可识别代码)
.o :可重定位目标文件,在vs2022中会形成xxx.obj
• 汇编阶段是把编译阶段⽣成的“.s”⽂件转成⽬标⽂件
• 读者在此可使⽤选项“-c”就可看到汇编代码已转化为“.o”的⼆进制⽬标代码了
• 实例: gcc –c hello.s –o hello.o
4 连接(⽣成可执⾏⽂件或库⽂件)
• 在成功编译之后,就进⼊了链接阶段。
• 实例: gcc hello.o –o hello
2.动态链接和静态链接
在我们的实际开发中,不可能将所有代码放在⼀个源⽂件中,所以会出现多个源⽂件,⽽且多个源⽂
件之间不是独⽴的,⽽会存在多种依赖关系,如⼀个源⽂件可能要调⽤另⼀个源⽂件中定义的函数,
但是每个源⽂件都是独⽴编译的,即每个*.c⽂件会形成⼀个*.o⽂件,为了满⾜前⾯说的依赖关系,则
需要将这些源⽂件产⽣的⽬标⽂件进⾏链接,从⽽形成⼀个可以执⾏的程序。这个链接的过程就是静
态链接。静态链接的缺点很明显:
• 浪费空间:因为每个可执⾏程序中对所有需要的⽬标⽂件都要有⼀份副本,所以如果多个程序对
同⼀个⽬标⽂件都有依赖,如多个程序中都调⽤了printf()函数,则这多个程序中都含有
printf.o,所以同⼀个⽬标⽂件都在内存存在多个副本;
• 更新⽐较困难:因为每当库函数的代码修改了,这个时候就需要重新进⾏编译链接形成可执⾏程
序。但是静态链接的优点就是,在可执⾏程序中已经具备了所有执⾏程序所需要的任何东西,在
执⾏的时候运⾏速度快。
动态链接的出现解决了静态链接中提到问题。动态链接的基本思想是把程序按照模块拆分成各个相对
独⽴部分,在程序运⾏时才将它们链接在⼀起形成⼀个完整的程序,⽽不是像静态链接⼀样把所有程
比特就业课
序模块都链接成⼀个单独的可执⾏⽂件。
动态链接其实远⽐静态链接要常⽤得多。⽐如我们查看下 hello 这个可执⾏程序依赖的动态库,会发
现它就⽤到了⼀个c动态链接库:
$ ldd hello
linux-vdso.so.1 => (0x00007fffeb1ab000)
libc.so.6 => /lib64/libc.so.6 (0x00007ff776af5000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff776ec3000)
在这⾥涉及到⼀个重要的概念: 库
• 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该
函数的声明,⽽没有定义函数的实现,那么,是在哪⾥实“printf”函数的呢?
• 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库⽂件中去了,在没有特别指定
时,gcc 会到系统默认的搜索路径“/usr/lib”下进⾏查找,也就是链接到 libc.so.6 库函数中去,这样
就能实现函数“printf”了,⽽这也就是链接的作⽤
静态库和动态库
ldd code(一个可执行文件) 可以查看它依赖那些库
动态库: linux(.so) windows(.dll)
静态库: Linux(.a) windows(.lib)
静态库:你每次写作业都要自己带铅笔橡皮
动态库:全班共用一套彩笔和削笔刀
这样理解的话,动静态库的核心区别就是
静态库 = 每个项目独占资源(占用空间多)
动态库 = 全局共享资源(节省空间易维护)
• 静态库是指编译链接时,把库⽂件的代码全部加⼊到可执⾏⽂件中,因此⽣成的⽂件⽐较⼤,但在运
⾏时也就不再需要库⽂件了。其后缀名⼀般为“.a”
• 动态库与之相反,在编译链接时并没有把库⽂件的代码加⼊到可执⾏⽂件中,⽽是在程序执⾏时由
运⾏时链接⽂件加载库,这样可以节省系统的开销。动态库⼀般后缀名为“.so”,如前⾯所述的
libc.so.6 就是动态库。gcc 在编译时默认使⽤动态库。完成了链接之后,gcc 就可以⽣成可执⾏⽂
件,如下所⽰。 gcc hello.o –o hello
• gcc默认⽣成的⼆进制程序,是动态链接的,这点可以通过 file 命令验证。
📌 注意1:
• Linux下,动态库XXX.so, 静态库XXX.a
• Windows下,动态库XXX.dll, 静态库XXX.lib