目录
一、gcc/g++的介绍
二、一个程序的翻译过程
2.1 预处理阶段
2.2 编译阶段
2.3 汇编阶段
2.4 链接阶段
三、动静态库简介
四、动静态库的优缺点
一、gcc/g++的介绍
首先,先简单的介绍一下gcc/g++。
GCC(GNU Compiler Collection)是一个由GNU项目开发的编译器集合,它能够编译多种编程语言,包括C、C++、Objective-C、Fortran、Ada等。GCC被广泛应用于各种操作系统和平台上,并且支持多种处理器架构。
其中,g++是GCC的C++编译器前端,它专门用于编译C++代码。g++在GCC的基础上增加了对C++语言的支持,包括对C++标准库的支持、C++特有的语法和特性等。使用g++可以将C++源代码编译成可执行文件或者库文件。
总的来说,GCC是一个通用的编译器集合,而g++是其中用于编译C++代码的一个组件。在使用时,可以通过调用gcc或者g++来进行编译,具体取决于需要编译的源代码类型。
简单来说,就是可以用gcc去编译c语言文件,g++去编译c++文件。
之前我们说过Linux下皆文件,后缀对Linux来说没什么意义,但这并不意味着对Linux上的程序和软件来说没意义,这点需要大家分清楚。
那么,我们要怎么使用gcc/g++呢?(这里用gcc举例,假设有一个文件名叫code.c)
gcc code.c (正常编译,然后系统会产生一个a.out的可执行文件)
gcc code.c -o myfile.exe (将编译的结果放如myfile.exe文件中,如果没有就创建)
如要执行一个可执行文件, ./ 加文件名就可以了,. 表示当前目录下 , / 表示执行。
这里还给大家列举一些gcc/g++会使用到的一些选项:
- -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
- -S 编译到汇编语言不进行汇编和链接
- -c 编译到目标代码
- -o 文件输出到 文件
- -static 此选项对生成的文件采用静态链接
- -g 生成调试信息。GNU 调试器可利用该信息。
- -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
- -O0
- -O1
- -O2
- -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高-w 不生成任何警告信息。
- -Wall 生成所有警告信息。
二、一个程序的翻译过程
2.1 预处理阶段
预处理主要干以下几件事:
- 头文件展开
- 去注释
- 条件编译
- 宏替换
那我们要怎么验证这个阶段呢?
我们可以通过gcc去看,代码如下:
gcc -E code.c -o code.i
(选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程)
通过运行这行指令,我们得到了一个code.i 文件,接下来我们可以通过vim查看一下。
不难发现,我们的头文件展开了,注释也去掉了,大家可以自行尝试观察一下。
2.2 编译阶段
编译阶段的主要工作:
将我们的代码翻译成汇编指令。
我们同样可以通过Linux的指令来查看这个过程,指令如下:
gcc -S code.i -o code.s
(“-S”选项用来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。为什么这里用code.i 而不是code.c,其实两个都可以,只是用code.c的话要重新进行预处理,code.i直接就能用)
同样,通过运行这段指令,生成了一个code.s的文件,我们可以同样使用vim进行查看。
可以发现,原来的c语言代码全都被替换成了汇编代码。
2.3 汇编阶段
汇编阶段的主要任务就是:
将汇编代码转换成可进行重定位的二进制文件。
这也可以通过Linux指令去查看这个过程,代码如下:
gcc -c code.s -o code.o
(使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了)
如果这个时候我们通过vim指令进行查看code.o文件,会看到一堆乱码。
不过我们可以通过od指令查看二进制文件
2.4 链接阶段
链接阶段的主要任务就是:
形成可执行文件。
简单来说,就是所有的.o文件+系统库=可执行文件。
三、动静态库简介
在我们写程序的时候,我们会发现我们明明没有实现输出的功能,却可以用printf这个函数将想要的内容打印到显示器上。
这是因为我们使用这个函数是有前提的,我们需要包含一个stdio.h的头文件,这其实就是我们的前辈写好的库,而我们程序如果要用printf这个函数的话,就需要依赖于第三方库。
在Linux中,我们可以使用相关指令去查看我们引用了哪些第三方库。
ldd(list dynamic dependencies)是一个用于查看可执行文件或者共享库文件所依赖的动态链接库的命令。它在Linux系统上常被用来检查程序运行时需要的共享库信息。
使用ldd命令可以列出一个可执行文件或者共享库文件所依赖的动态链接库及其路径,以及这些动态链接库是否能够被找到。这对于调试程序运行时出现的库依赖问题非常有用。
使用格式:
ldd + 想要查看的可执行程序
我们这里同样拿上面的例子进行举例:
可以发现我们引用了 libc.so.6 这个库,那他这个库是什么意思呢,我们现在来解读一下。
在这就不得不提到一个概念 动静态库。
动态库:是C/C++或者其他第三方提供的所有方法的集合,被所有程序以链接的方式关联起来。
静态库:是C/C++或者其他第三方提供的所有方法的集合,被所有程序以拷贝的方式,将需要的代码,拷贝到自己的可执程序当中。
在Linux中,动态库常以 .so 为后缀,静态库常以 .a为后缀。
在Windows中,动态库常以 .dull为后缀,静态库常以 .lib为后缀。
四、动静态库的优缺点
上面我们已经提到过了动静态库的定义,简单来说,动态库就是根据其提供的地址去调用我们要使用的函数。而静态库则是给你整个代码全搬过来。由此我们来分析其优缺点:
动态库:
优点:形成的可执行程序体积比较小,比较节省资源。
缺点:会稍微慢一点,且程序强依赖于动态库,这个库一旦没了,所有依赖于此库的程序都无法运行了。
静态库:
优点:无视库,可以独立运行
缺点:体积太大,浪费资源
在Linux中,静态库默认是没有安装的,那我们可以通过以下指令来安装
c语言静态库: sudo yum install glibc-static
c++静态库:sudo yum install -y libstdc++-static
同样我们也可以用静态库来运行程序,例如:
gcc code.c -static
运行结果都是一样的,就是用ldd查看库的结果不一样。