目录
⭐前言
编译器的处理过程:
- 预处理(进行宏替换)
- 编译(生成汇编)
- 汇编(生成机器可识别代码)
- 链接(生成可执行文件或库文件)
更加详细的介绍,可以参照这篇博客:C语言翻译环境:预编译+编译+汇编+链接详解-CSDN博客
⭐gcc/g++介绍
GCC(GNU Compiler Collection)是一个由GNU项目开发的编译器套件,它包括了用于多种编程语言的编译器,如C、C++、Fortran、Ada、Go等。GCC是一个开源的工具集,可在多个平台上运行,支持多种操作系统和架构。它是许多操作系统的默认编译器,也是许多开源项目的首选编译工具。
在GCC中,gcc和g++分别是用于编译C和C++代码的编译器。
-
gcc:
- 功能:gcc是GCC套件中用于编译C语言代码的编译器。它将C源代码编译成目标代码,并调用GCC的后端来生成可执行文件或库文件。
- 特点:gcc支持多种C语言标准,如ANSI C(C89/C90)、C99和C11。开发人员可以使用gcc来编译符合不同C语言标准的代码,并生成与目标平台兼容的可执行文件。
- 选项:gcc提供了丰富的编译选项和优化选项,开发人员可以通过这些选项来控制编译过程中的各种行为,如优化级别、调试信息、警告设置等。
-
g++:
- 功能:g++是GCC套件中用于编译C++代码的编译器。它是gcc的C++编译器前端,通过调用GCC的后端来生成目标代码。
- 特点:g++支持多种C++标准,如C++98、C++11、C++14、C++17等。开发人员可以使用g++来编译符合不同C++标准的代码,并生成高效的可执行文件或库文件。
- 选项:与gcc类似,g++也提供了丰富的编译选项和优化选项,可以帮助开发人员优化编译过程并生成高效的目标代码。
除了编译器之外,GCC还包括了一些其他工具,如预处理器、汇编器、链接器等,可以帮助开发人员完成整个编译过程。
⭐gcc/g++的编译指令(以gcc为例)
首先可以查看一下自己的Linux上gcc的版本,确认是否有gcc编译器。
gcc --version
⚡gcc选项
- -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
- -S 编译到汇编语言不进行汇编和链接
- -c 编译到目标代码
- -o 文件输出到 文件
- -static 此选项对生成的文件采用静态链接
- -g 生成调试信息。GNU 调试器可利用该信息。
- -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
- -O0,-O1,-O2,-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
- -w 不生成任何警告信息。
- -Wall 生成所有警告信息
⚡预处理(进行宏替换)
- 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
- 预处理指令可以让编译器进行完预处理过程后,就停止,生成目标文件。
- 实例: gcc -E test.c -o test.i
- 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
- 选项“-o”是指目标文件,-o filename 可以指定生成的可执行文件的名称,“.i”文件为已经过预处理的C原始程序。
⚡编译(生成汇编)
- 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
- 用户可以使用 “-S” 选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
- 实例: gcc -S test.i -o test.s
⚡汇编(生成机器可识别代码)
- 汇编阶段是把编译阶段生成的“.s”文件转成目标文件
- 使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了
- 实例: gcc -c test.s -o test.o
⚡链接(生成可执行文件或库文件)
- 在成功编译之后,就进入了链接阶段。
- 实例: gcc test.o -o test.exe
上述的四个指令,实际上在使用时都被压缩成了一条指令,直接编译:
gcc test.c -o test
⭐函数库
⚡概念
函数库(Library)是一种预先编写好的、可重用的代码集合,其中包含了一系列函数、类或其他程序组件,用于执行特定的任务或提供特定的功能。函数库通常以文件或模块的形式存在,可以在程序中引用和调用其中的函数来完成相应的操作。
比如我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那我们为什么可以使用这个函数呢?
实际上,系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。
⚡动态库和静态库
-
静态库(Static Library):
- 静态库在编译时被链接到可执行文件中,编译后的可执行文件包含了静态库中的代码。
- 每个使用了静态库的可执行文件都会包含一份静态库的副本,因此可执行文件体积较大。
- 静态库的代码在编译时被复制到可执行文件中,程序运行时不需要外部库文件。
- 静态库的文件扩展名通常为
.lib
(Windows)或.a
(Unix/Linux)。
-
动态库(Dynamic Library):
- 动态库在程序运行时才加载到内存中,可执行文件只包含对动态库的引用。
- 多个程序可以共享一份动态库,减少内存占用和磁盘空间。
- 动态库的代码在程序运行时动态加载,可能会造成一定的性能损失。
- 动态库的文件扩展名通常为
.dll
(Windows)或.so
(Unix/Linux)。
gcc的默认链接方式是链接动态库,我们可以手动修改为链接静态库:
gcc -static test.c -o test-static
可以发现通过链接静态库生成的可执行程序的大小远远大于通过链接动态库生成的可执行程序的大小。
gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。
file+filename//查看文件类型
____________________
⭐感谢你的阅读,希望本文能够对你有所帮助。如果你喜欢我的内容,记得点赞关注收藏我的博客,我会继续分享更多的内容。⭐