1.gcc/g++
gcc是对c语言代码进行编译链接,而g++是对c++代码进行编译链接,接下来我们只对gcc进行讲解,g++的使用方法跟gcc是一样的。
编译链接的四个步骤:
1:预处理
2:编译
3:汇编
4:链接
注:这些在后面都会着重讲解
1.1gcc -o
我们先在Date.c 源文件里面写一些c语言代码,我们知道,c语言代码需要编译链接翻译为计算机能识别的二进制指令才能执行。而gcc就是Linux环境下用来对c语言代码编译链接的指令.
gcc 源文件 -o 生成指定的文件名
gcc Date.c -o date.aout
注:这里会一步到位,直接会生成一个可执行程序,接下来我们再一步一步分析具体细节
1.2gcc -E (预处理)(.i)
预处理:头文件展开、去注释、宏替换、条件编译
-E:当程序进行翻译时,预处理阶段执行完就停下来
gcc Date.c -o date.aout -E
头文件展开:#include<stdio.h>这个文件里面有很多函数的声明和typedef的内容,头文展开会将stdio.h这个文件中所有的内容复制一份到我们的date.i文件中。
去注释:会将我们注释的内容替换为空格。
1.3gcc -S (编译)(.s)
编译:将c语言写的内容翻译为汇编语言
-S:当程序进行翻译时,编译阶段执行完就停下来
gcc Date.c -o date.s -S
1.4gcc -c (汇编)(.o)
汇编:将汇编语言翻译为二进制语言。
-c:当程序进行翻译时,编译阶段执行完就停下来
gcc Date.c -o date.o -c
1.5gcc -o (链接)
当我们不带-E、-S、-c这些选项时,直接-o,gcc就会一步到位从预处理阶段到编译,再到汇编,最后到链接!!!
在我们上面写的c语言代码中,我们并没有写printf函数的具体实现,而在<stdio.h>这个文件中也只有printf函数的声明而没有其具体实现的定义,那么我们再使用printf这个函数的时候怎么去调用这个函数呢?
在Linux Centos7 环境下,系统把这些函数的具体实现都放在了一个名为libc.so.6的库文件中了,路径为/usr/lib/libc.so.6,当我们调用printf函数时,会去libc.so.6库文件中去寻找printf实现的实现方法,最终成功调用。
我们可以使用ldd + 可执行程序 来查看该可执行程序依赖了那些库文件
2.动态库/静态库
2.1.再谈链接
链接的时候,我们是怎么去库文件中寻找函数具体实现的方法的呢?
有两种情况,一种是我们得到函数的地址,在生成可执行程序时根据地址去调用这个函数,另一种则是我们得到这个函数的整体实现过程,在生成可执行程序时将函数实现的代码加载进来。
根据链接方式的不同,库文件也就分成了两种:动态库/静态库,动态库使用动态链接,静态库使用静态链接。
2.2动态库
注:gcc在编译时默认使用动态库!!!优点:比较节省资源(磁盘、内存、网络等资源),不会出现太多重复代码缺点:太过于依赖库,一旦库缺失,所有使用该库的程序都不能运行!!!
2.3静态库
优点:不依赖库,同类型平台中可以直接运行使用。缺点:可执行程序占用空间比较大,比较浪费资源(磁盘、内存、网络等资源)
gcc编译时使用-static选项可以在链接时使用静态链接的方式链接静态可。
gcc -o mybin-static test.c -static
但是我们直接执行的话会出现问题,这里的原因是因为我们的系统中没用静态库,导致静态链接失败。我们可以使用yum命令下载c/c++的静态库,在root用户下执行,或者使用sudo命令。如果不清楚yum命令的可以看我这一篇博客http://t.csdnimg.cn/M1JLr
sudo yum install -y glibc-static libstdc++-static
安装好静态库之后 我们再进行一次编译gcc -o mybin-static test.c -static
由图可知,静态链接静态库生成的可执行程序比动态链接动态库生成的可执行程序要大得多