💗个人主页💗
⭐个人专栏——Linux学习⭐
💫点击关注🤩一起学习C语言💯💫
目录
- 导读
- 1. Linux编译器-gcc/g++使用
- 1.1 引入
- 1.2 初识gcc/g++
- 1.3 程序运行的四个阶段
- 1.3.1 预处理
- 1.3.2 编译
- 1.3.3 汇编
- 1.3.4 链接
- 1.4 gcc的选项用法
- 2. 函数库
- 2.1 引入
- 2.2 函数库分类
- 2.3 动态库
- 2.4 静态库
导读
我们上次讲到yum命令和vim指令的运用,今天我们来讲一下gcc,
1. Linux编译器-gcc/g++使用
1.1 引入
我们在之前,也在Linux里写过C语言的代码,之后gcc加文件名运行之后,在运行./a.out.
[zhy@centos7 ~]$ vim project.c
[zhy@centos7 ~]$ gcc project.c
[zhy@centos7 ~]$ ./a.out
功能2
功能3
功能4
1.2 初识gcc/g++
在Linux中,gcc和g++是常用的编译器,分别用于编译C和C++程序。
gcc是GNU Compiler Collection的缩写,是一个开源的编译器集合,支持多种编程语言,包括C、C++、Objective-C、Fortran等。因此,gcc可用于编译C、C++等多种语言的程序。它可以把C++源代码交给g++编译器处理,也可以处理其他语言的源代码。
g++是gcc的一个衍生版,专门用于编译C++程序。它是gcc的C++编译器前端,对于C++语言的特性和标准库提供更好的支持。相比于gcc,g++对C++的语法和特性更加敏感和严格。
编译C程序:
-
编写C代码(例如,将代码保存为hello.c)。
-
打开终端,并切换到保存C代码的目录。
-
使用以下命令编译C代码:
[zhy@centos7 ~]$ gcc -o project project.c
该命令将使用gcc编译器将project.c源文件编译为可执行文件project。
4. 运行可执行文件:
[zhy@centos7 ~]$ ./project
编写C++程序同理,知识命令从gcc变为g++。
那么,他们都经历过什么步骤呢?
1.3 程序运行的四个阶段
一般gcc会默认执行四个步骤:预处理、编译、汇编、链接。
1.3.1 预处理
预处理阶段通过预处理器(如gcc、g++)对源代码进行处理。
主要包括:
- 宏替换
- 头文件包含
- 条件编译
- 去除注释
预处理器根据预处理指令(以#开头)对源代码进行修改和展开,生成经过预处理后的新代码。
运行以下命令:
[zhy@centos7 ~]$ gcc -E project.c -o project.i
将会生成一个project.i的文件,里面是源文件经过预处理之后的代码。
选项 -E:该选项的作用是让 gcc 在预处理结束后停止编译过程。
选项 -o:是指目标文件,.i为后缀的文件为已经过预处理的C原始程序。
1.3.2 编译
编译阶段将预处理后的代码编译为汇编代码。
编译器经过**词法分析、语法分析、语义分析、以及之后的优化**将源代码翻译成汇编语言,生成汇编代码(以汇编语言表示的低级指令)。
[zhy@centos7 ~]$ gcc -S project.i -o project.s
将会生成一个project.s的文件,里面存入的是汇编代码。
选项-S:该选项只进行编译而不进行汇编,生成汇编代码。
1.3.3 汇编
汇编阶段将汇编代码转换成机器码指令。
汇编器(如gcc、nasm)将汇编代码转换为可执行的机器指令,也就是二进制码。每个汇编语句都直接对应于一条机器指令。
[zhy@centos7 ~]$ gcc -c project.s -o project.o
我们发现,这个生成的.o文件,为何打开是乱码?
.o后缀文件是编译阶段生成的目标文件,它包含汇编代码和符号信息,不是可执行文件,我们可以使用objdump命令,这个命令是GNU Binutils工具集中的一个工具,可以用来查看目标文件的内容。
[zhy@centos7 ~]$ objdump -d project.o
显示.o文件中的反汇编代码,以及对应的机器指令。
1.3.4 链接
链接阶段将多个目标文件和库文件合并在一起,生成最终的可执行文件。
链接器(如ld、gcc、g++)解决了不同目标文件之间的符号引用关系,将这些目标文件以及所需的库文件合并在一起,生成可执行文件。在此阶段,还进行了地址重定位、符号解析等操作。
也就是我们上述执行过的一个命令,为了再次演示,我们先把之前生成的执行文件删除,然后再次执行。
[zhy@centos7 ~]$ rm -f project
[zhy@centos7 ~]$ gcc -o project project.c
[zhy@centos7 ~]$ ./project
1.4 gcc的选项用法
我们上面通过一些选项,选择让gcc生成我们所需要的文件,那么gcc还有些什么功能选项呢。
- -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
- -S 编译到汇编语言不进行汇编和链接
- -c 编译到目标代码
- -o 文件输出到 文件
- -static 此选项对生成的文件采用静态链接
- -g 生成调试信息。GNU 调试器可利用该信息。
- -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
- -O0
- -O1
- -O2
- -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
- -w 不生成任何警告信息。
- -Wall 生成所有警告信息。
2. 函数库
2.1 引入
在上面的程序中,涉及到了一个重要的概念:函数库。
我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。
2.2 函数库分类
在Linux中,函数库是一组预编译的代码,提供了许多可重用的函数和工具,可以帮助开发人员更快速地构建和开发应用程序。
以下是Linux中常见的几种函数库:
-
标准C函数库(libc):这是Linux系统中最基本的函数库,提供了C语言标准函数的实现。它包含了对文件操作、字符串处理、内存管理、数学运算等常用功能的支持。以glibc(GNU C Library)为例,它是Linux系统中最常用的C函数库。
-
动态链接库(shared library):动态链接库是一种可以在运行时加载的共享库,提供了一组函数和符号供应用程序使用。动态链接库以 .so(shared object)为文件后缀。常见的动态链接库包括 libm(数学库)、libpthread(线程库)等。它们在编译时不会被静态地链接到可执行文件,而是在运行时动态加载。
-
静态链接库(static library):静态链接库是一组在编译时被静态地链接到可执行文件的函数和符号。静态链接库以 .a(archive)为文件后缀。静态链接库可以包含多个目标文件,可以通过 ar 命令创建和管理。
-
POSIX函数库:POSIX(Portable Operating System Interface)函数库是一组用于支持Unix/Linux标准接口的函数库,涵盖了文件操作、进程管理、信号处理、线程等方面的功能。常见的POSIX函数库包括 libpthread(线程库)、libdl(动态加载库)等。
当然还有其他的函数库,今天我们主要来学习动态库和静态库。
需要注意的是,当静态库和动态库都存在时,编译器优先选择动态库进行链接。
如果希望强制使用静态库进行链接,可以使用 -static 参数。
2.3 动态库
动态库是一组在运行时加载的共享库,它与可执行文件是分离的。动态库的扩展名通常是.so(shared object)。
💫使用方式💫
- 在编译时,可以使用 -l 和 -L 参数来指定需要链接的动态库及其位置。例如:-lmylib 表示链接名为 libmylib.so 的动态库。
- 在运行时,系统会自动查找并加载程序所需要的动态库。
💫ldd命令💫
ldd命令是在Linux系统中用于检查可执行文件或共享库所依赖的动态链接库的工具。它可以显示出一个可执行文件或共享库所需的动态链接库列表。
[zhy@centos7 ~]$ which ldd
/usr/bin/ldd
[zhy@centos7 ~]$ ldd project
linux-vdso.so.1 => (0x00007ffc30ba0000)
libc.so.6 => /lib64/libc.so.6 (0x00007fe4e8e59000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe4e9227000)
💫优势💫
动态库可以在多个程序之间共享,减少了内存占用和可执行文件的体积。如果对动态库进行更新,所有使用该库的程序都可以受益。
2.4 静态库
静态库是一组在编译时被静态地链接到可执行文件的函数和符号。静态库的扩展名通常是 .a(archive)。
💫使用方式💫
在编译时使用 -l 和 -L 参数来指定需要链接的静态库及其位置。例如:-lmylib 表示链接名为 libmylib.a 的静态库。
与动态库不同的是:C和C++静态库需要我们自己去安装。
sudo yum install -y glibc-static
sudo yum install -y libstdc++-static
💫优势💫
静态库在编译时会被完整地复制到可执行文件中,使得可执行文件成为一个独立的单元,不依赖于外部库文件。