目录
一、背景知识
二、gcc是如何完成的
1、预处理(进行宏替换)
2、编译(生成汇编)
3、汇编(生成机器可识别代码)
4、链接(生成可执行文件或库文件)
4.1、静态库
4.2、动态库
4.3、动静态库的比较
三、gcc常见的选项
一、背景知识
计算机是二进制读取文件的,我们写好代码是经过编译,链接,然后形成可执行程序。
1、预处理(进行宏替换);
2、 编译(生成汇编) ;3、汇编(生成机器可识别代码) ;
4、连接(生成可执行文件或库文件) .
二、gcc是如何完成的
1、预处理(进行宏替换)
- 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
- 预处理指令是以#号开头的代码行。
- 实例: gcc –E hello.c –o hello.i
- 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
- 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
如下是Linux运行结果:
并且生成如下的test.i的文件,
可以看出在test.i文件中的注释已经去掉,宏已经被替换了。
2、编译(生成汇编)
- 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
- 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
- 实例: gcc –S hello.i –o hello.s
此时又生成一个test.s的文件,
虽然看的不太懂,但是我们经过前段时间的学习,大概能够看出这是汇编代码。
3、汇编(生成机器可识别代码)
- 汇编阶段是把编译阶段生成的“.s”文件转成目标文件;
- 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了;
- 实例: gcc –c hello.s –o hello.o.
此时已经将汇编代码转换成了“.o”的二进制目标代码了。
注意:此时还没有进行链接,所以是不可执行的。
4、链接(生成可执行文件或库文件)
- 在成功编译之后,就进入了链接阶段。
- 实例: gcc hello.o –o hello.
链接之后生成了可执行文件,此时就可以运行了。
链接:
- 静态链接:编译器的链接器此时会将我们的程序以静态链接的形式与静态库进行链接。
- 动态链接:编译器的链接器此时会将我们的程序以动态链接的形式与动态库进行连接。
执行 ldd + test 命令可以看出是静态链接还是动态链接 。
可以看出是动态链接。Linux下:动态库是以.so结尾的,静态库是以.a结尾的。
下面接着介绍一下动静态库:
4.1、静态库
- 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也 就不再需要库文件了。其后缀名一般为“.a”
- 实例:gcc test.c -o test-static -static
可以看出静态链接和动态链接的文件大小差距还是很大的,静态链接生成的文件比较占用空间。
静态库的命名为:libXXX.a
- lib 是前缀
- .a 是后缀
- XXX 是真正的库
通过file 命令可以查看详细信息
静态链接 : 因为是直接将需要的代码拷贝到程序中,因此最终生成的文件会变大,比较占空间。
4.2、动态库
- 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时 链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态 库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。 gcc hello.o –o hello;
- gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。
静态库的命名为:libXXX.so
- lib 是前缀
- .so 是后缀
- XXX 是真正的库
动态链接 :主要依赖不同函数在库中的位置信息进行调用,只有一份代码库,比较节省空间。
4.3、动静态库的比较
静态库:
优点:(1)所需函数直接拷贝至程序中,运行速度快;(2)程序运行不依赖库,便于移植。
缺点:(1)如果将函数进行修改,需要重新进行编译;(2)同一份代码可能出现重复拷贝的情况,浪费空间。
动态库:
优点:(1)可以实现不同进程间的资源共享;(2)对于函数的修改只需要替换动态库文件即可,不需要重新编译程序。
缺点:(1)需要调用函数,运行速度较慢;(2)程序运行需要依赖动态库。
三、gcc常见的选项
- -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面;
- -S 编译到汇编语言不进行汇编和链接;
- -c 编译到目标代码;
- -o 文件输出到 文件;
- -static 此选项对生成的文件采用静态链接;
- -g 生成调试信息。GNU 调试器可利用该信息;
- -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库;
- -O0;
- -O1;
- -O2;
- -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高;
- -w 不生成任何警告信息;
- -Wall 生成所有警告信息.
本文要是有不足的地方,欢迎大家在下面评论,我会在第一时间更正。