【Linux】gcc编译器的使用(程序的翻译过程)
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目 录
程序的翻译过程包括预处理、编译、汇编、链接四个部分接下来文章中将讨论在Linux下如何使用gcc编译器完成程序的翻译。
1 程序的翻译
gcc使用命令格式
gcc [选项] 要编译的文件 [选项] 生成的目标文件
以下以 test.c
文件作为示例讨论程序翻译过程其中源代码如下图所示
1.1预处理进行宏替换
- 预处理功能主要包括宏定义文件包含条件编译去注释等。
- 预处理指令是以
#
号开头的代码行。 - 使用gcc完成预处理过程
gcc -E test.c -o test.i
其中选项-E
的作用是让gcc在预处理结束后停止编译过程选项-o
是指生成目标文件注意-o 选项后面必须紧跟目标文件.i
文件是经过预处理后的C原始程序如下图所示源程序中的注释经过预处理后被删去了main函数中的N也被替换为了100还有条件编译也被处理了此外还可以看到除了被处理后的原代码部分前面还有八百多行代码是头文件等展开后的结果。
1.2 编译生成汇编代码
- 编译过程包括词法分析、语法分析、语义分析等。在这个过程中gcc首先要检查代码的规范性、是否有语法错误等以确定代码实际要做的工作在检查无误后gcc把代码翻译成汇编语言程序。
- 使用gcc完成编译过程
gcc -S test.i -o test.s
其中-S
的作用是让gcc在编译结束后停止翻译过程.s
文件是编译后生成的汇编语言程序如下图所示。
1.3 汇编生成机器可识别代码
- 汇编阶段就是把编译阶段生成的
.s
文件转成目标文件。 - 使用gcc完成汇编过程
gcc -c test.s -o test.o
其中-c
的作用是让gcc在汇编结束后停止翻译过程.o
文件是汇编后生成的可重定位目标二进制代码相当于windows下程序翻译后形成的.obj
文件。如下图所示这里只是把我们自己编写的代码翻译成了二进制文件即使将文件权限修改为可执行后这个二进制文件仍是不可被执行的还需经过链接过程形成完整的可执行程序。
1.4 链接生成可执行文件或者库文件
- 使用gcc完成链接过程
gcc test.o -o test
链接过程具体做了什么呢这里需要先了解一个概念函数库 。
- 我们在编写程序时常常会用到
printf
等库函数但事实上在预编译中包含的头文件stdio.h
中也只是有函数的声明而没有函数的定义实现那printf
又是在哪里实现的我们的程序又是如何成功使用函数的呢
其实系统把这些函数实现都写在名为libc.so.6
的库文件中了在没有特别指定时gcc会到系统默认的搜索路径/usr/lib
下查找也就是链接到libc.so.6
库函数中去如此就能实现对应的库函数了而这也是链接的作用。- 我们之所以能够在Linux下进行C、C++等代码的编写和编译是因为Linux系统默认已经携带了语言级别的头文件和语言对应库而编译器能够自动帮我们识别解释这些语言并根据相应的库完成程序的编译链接以形成可执行程序。
函数库一般分为静态库和动态库共享库两种对应的链接也分为静态链接和动态链接
- 库本质上也是一种文件Linux下静态库通常以
libXXX.a
的形式命名动态库通常以libXXX.so
的形式命名Windows下静态库通常以.lib
为后缀动态库通常以.dll
为后缀。 - 静态链接是指在编译链接时把静态库中我们所需要的代码全部拷贝添加到最终的可执行文件中因此生成的文件比较大会比较占用空间但同时静态链接完成后程序在运行时也就不需要再依赖任何库自己就可以运行了。
- 与静态链接不同动态链接在程序编译链接时并没有把库文件中的代码拷贝添加到可执行文件中而是将动态库文件中我们所需要的代码的地址拷贝添加到可执行文件中的相关位置程序运行时则通过地址链接库文件找到相应的代码。如此所有有需要的程序共享方法而方法的真正实现永远只在库中可有效节省系统的开销。但如果相关动态库缺失对应的程序也将无法执行。
那我们要如何知道我们的可执行程序是静态链接形成的还是动态链接形成的呢这里首先要了解一个命令ldd 可执行文件
通过该命令可以查看对应可执行文件所依赖的动态库。
以下通过示例来进一步了解程序的链接
- 需要注意的是Linux下默认使用的是动态链接和动态库。
那如何实现静态链接呢
这里使用的是云服务器一般云服务器默认只有动态库如果要实现静态链接还需安装静态库否则会报错。我们可以通过命令
yum install glibc-static libstdc++-static -y
来安装静态库。接着通过命令gcc test.o -o test-static -static
实现静态链接这里为了区分动态链接形成的可执行文件将静态链接形成的可执行文件命名位 test-static
。命令中选项 -static
表示使用静态链接和静态库。如下图所示可以看到静态链接形成的可执行文件的大小约有动态链接形成的可执行文件的大小的100倍可见静态链接消耗的空间之大。
总结 以上为了更加详细的了解程序翻译的过程所以分四步完成程序的翻译在实际中如果没有特殊需要以test.c文件的翻译为例可直接使用命令
gcc test.c -o test
完成程序的编译及动态链接使用命令gcc test.c -o test -static
完成程序的编译及静态链接其中如果不加选项-o test
生成指定的目标文件则会默认生成名为a.out
的可执行文件。 如下图所示无论是动态链接形成的可执行程序还是静态链接形成的可执行程序又或是默认形成的可执行程序最终的运行结果都是一样的。
1.5 gcc常用选项总结
-E
只激活预处理不生成文件需要将执行结果重定向到一个输出文件中否则默认将预处理结果输出到屏幕。-S
编译到形成汇编语言代码就停止不进行汇编和链接。-c
编译到形成二进制目标代码。-o
输出指定目标文件。-static
对生成的二进制文件采用静态链接。-g
生成调试信息Debug版可执行程序。GUN调试器可利用该信息。-shared
尽量使用动态库形成的可执行文件比较小但前提需要系统有动态库。-O0
、-O1
、-O2
、-O3
编译器的优化选项的4个级别-O0
表示没有优化-O1
为缺省值-O3
优化级别最高。-w
不生成任何警告信息。-Wall
生成所有警告信息。
以上是我对Linux中gcc编译器使用的一些学习记录总结如有错误希望大家帮忙指正也欢迎大家给予建议和讨论谢谢