gcc/g++
- 一,简介
- 二,代码的翻译过程
- 1,预处理
- 2,编译
- 3,汇编
- 4,链接
- (1)静态库
- (2)动态库
- (3)动静态库比较
- 三,常见选项
一,简介
我们知道,计算机是只能识别二进制的,那么我们写的代码是怎么运行的呢?
代码是经过编译,链接,最终形成可执行程序的。
编译的过程又包括:预处理,编译,汇编,那么这些阶段都做了些什么呢?
利用gcc/g++,来介绍一下。
二,代码的翻译过程
1,预处理
gcc -E test.c -o test.i
gcc -E test.c 的意思是:从现在开始对程序进行翻译,到预处理结束后停止。
为了防止直接将预处理后的代码直接打印到屏幕上,可以加- o选项,意思是输出到指定的文件。
预处理阶段的工作
- 去注释
- 宏展开
- 头文件展开
- 条件编译
下面来验证一下:
可以看到test.c文件中 有宏的定义,条件编译,注释,包含了头文件,
预处理后文件内容的变化:
2,编译
在编译过程中,编译器会将原来的C代码转化成汇编代码,也可以使用gcc命令查看编译后的文件
gcc -S test.i -o test.s
3,汇编
汇编过程会把汇编代码转化为可重定位的二进制文件,虽然这里形成了二进制文件,但是再没有链接之前是不可被执行的。
gcc -c test.s -o test.o
看到上述场景是因为,vim是一个多模式的文本编辑器,所以它是以文本的方式对二进制文件进行解析,就呈现出上图的情况。
4,链接
链接阶段是将我们的程序链接相应的库,最终生成ELF格式的二进制文件,也就是可执行程序。
我们的程序中有许多功能是依赖于库实现的,例如:printf,scanf等功能的实现。
链接
- 静态链接
编译器的链接器此时会将我们的程序以静态链接的形式与静态库进行链接。 - 动态链接
编译器的链接器此时会将我们的程序以动态链接的形式与动态库进行连接。
(1)静态库
程序与静态库链接时,是把自己写的程序中用到库中的某项功能的代码直接拷贝到自己的程序中。
一旦链接成功,那么即使静态库出现问题,也不会影响程序的运行,但是同样也增加了程序的大小。
(2)动态库
程序与动态库进行链接的时候,是把自己写的程序中用到库中某项功能代码的地址拷贝到自己程序的相应位置,在程序运行时,再去库中实现这一功能。
因此,动态库也被称作共享库。
(3)动静态库比较
- 动态库是专门让编译器对用户的程序进行动态链接的,静态库是专门让编译器对用户的程序进行静态链接的。
- 动态链接是将动态库中的代码的地址,拷贝到用户程序的相应位置,静态链接是将静态库中的代码直接拷贝到用户程序中。
- 静态链接成功后,就不在依赖库,可以自己独立运行。
- 动态链接成功后,程序还是依赖于库,一旦动态库缺失,程序就无法运行。
- 静态链接由于直接拷贝代码,比较浪费空间
- 动态链接由于大家都共享动态库,所以比较省空间。
- Linux环境下,默认链接时,是动态链接。
静态链接
gcc test.c -o test-static -static
可以看到动态链接与静态链接形成的可执行文件的大小差距还是很大的。
Centos7安装C/C++静态库的方法
- C: sudo yum install -y glibc-static
- C++:sudo yum install -y libstdc++ -static
三,常见选项
-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
-S 编译到汇编语言不进行汇编和链接
-c 编译到目标代码
-o 文件输出到 文件
-static 此选项对生成的文件采用静态链接
-g 生成调试信息。GNU 调试器可利用该信息。
-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
-O0
-O1
-O2
-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
-w 不生成任何警告信息。
-Wall 生成所有警告信息。