【Linux】程序的翻译过程

简介: 【Linux】程序的翻译过程

程序的翻译过程分为:预处理、编译、汇编、链接

Linux中,我们可以用gcc命令的各种选项看到翻译的各过程,可以在每个阶段停下来,并且可以看到中间的翻译结果,这样就更便于我们理解翻译过程

1.预处理阶段

gcc -E

gcc -E test.c -o test.i

形成一个test.i文件,文件中保存的是gcc -E产生的临时结果

头文件展开

我们的test.c文件中只有24行,结果test.i中多出800多行,那多出来的这么多是什么呢?

其实这么多代码都是从stdio.h这个头文件展开来的

在预处理阶段,编译器会将我们源代码中所需要的头文件拷贝到源文件中来,我们的头文件中可能也会包含头文件,所以可能会进行递归的拷贝,这个过程叫做头文件展开

在安装编译器的时候,C标准库的头文件一般会一并下载到/usr/include/

我们可以打开stdio.h看一下

对比一下,确实我们展开的是stdio.h

我们可以看到预处理阶段进行了宏替换注释也被替换

条件编译

我们现在下载的软件,大多都分为好几个版本:专业版、社区版、学生版...

那这是怎么维护的呢,如果一个版本有一份源代码,那维护起来的成本是非常大的,这就可以用条件编译来解决这个问题了,只需要维护一份代码,可以用条件编译进行代码的动态裁剪

我们在C语言阶段就有过条件编译的说明:#ifdef #elif #else #endif

具体在《C语言 预处理》专栏的条件编译有说明

C语言 预处理详解-CSDN博客

我们编译成proj.i看一下

我们可以看到,满足条件的保留,不满足条件的删除

gcc -D 动态添加宏

我们可以不在文件中宏定义,可以通过gcc -D进行命令行式的宏定义,这样我们就可以动态地向源代码添加宏

2.编译阶段

预处理的结果是test.i,是一份干净的C语言代码

gcc -S

gcc -S test.i -o test.s

gcc -S产生一个test.s的临时结果

但是这个代码我们可能看不懂,但是我们知道这是汇编语言

3.汇编阶段

gcc -c

gcc -c test.s -o test.o

gcc -c 将test.s文件转成test.o文件,.o表示.obj,在vs中我们编译文件就会产生.obj文件

产生的.obj文件叫做目标文件,这个目标文件不能直接执行,最终形成.exe可执行程序才能运行

4.链接阶段

gcc test.o -o my.exe

只有最终形成可执行文件,才可以执行

关于链接,我们有三个问题:

  • 是什么?
  • 为什么?
  • 怎么办?

是什么?

链接的过程是我们的程序和库结合的过程

我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?

最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用

库:语言一定要有自己的标准库

我们可以用ldd命令来看到对应的动态库

这就是我们的C标准库

在安装开发环境的时候,会安装C标准库+C头文件,这时候我们才可以包含对应的头文件,调用头文件里声明的函数

函数库

函数库一般分为静态库和动态库两种

静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a

动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。

  • Linux中,动态库.so 静态库.a
  • Windows中,动态库.dll 静态库.lib

为什么?

  • 让开发站在巨人的肩膀上
  • 提高开发的效率

怎么办?

链接时,两种链接方式:

  • 动态链接
  • 静态链接

动态链接

动态库和动态链接的优缺点

  1. 不能丢失
  2. 节省资源

静态链接

静态库和静态链接的优缺点

  1. 一旦形成,和库无关
  2. 浪费资源

C动态库,是默认提供的

gcc默认形成的可执行程序,默认采用动态链接

而Linux中静态库默认是没有的

安装静态库我们可以用yum指令

sudo yum install -y glibc-static libstdc++-static

这时我们就可以编译通过了

同样运行也能通过

静态链接的应用场景

由于静态链接不依赖于任何的动态库,所以在移植到其他环境中时就不需要做过多的环境检测,可以直接运行,方便部署


相关文章
|
5天前
|
Linux 开发工具 C语言
Linux 安装 gcc 编译运行 C程序
Linux 安装 gcc 编译运行 C程序
24 0
|
存储 编译器
Linux--程序地址空间
Linux--程序地址空间
|
4天前
|
Java Shell Linux
【linux进程控制(三)】进程程序替换--如何自己实现一个bash解释器?
【linux进程控制(三)】进程程序替换--如何自己实现一个bash解释器?
|
1月前
|
Shell Linux C语言
【Shell 命令集合 系统设置 内置命令】⭐⭐Linux 测量程序的执行时间和资源使用情况 time命令 使用指南
【Shell 命令集合 系统设置 内置命令】⭐⭐Linux 测量程序的执行时间和资源使用情况 time命令 使用指南
33 0
|
1月前
|
前端开发 Unix Linux
Linux indent命令 (格式化C语言源代码的程序)
Linux indent命令 (格式化C语言源代码的程序)
18 0
Linux indent命令 (格式化C语言源代码的程序)
|
1月前
|
存储 缓存 安全
掌握Linux字符设备驱动程序的核心要点
掌握Linux字符设备驱动程序的核心要点
59 0
|
1月前
|
Shell Linux 调度
【Linux】—— 进程程序替换
【Linux】—— 进程程序替换
|
1月前
|
Java Linux Shell
进程的程序替换(exec函数)【Linux】
进程的程序替换(exec函数)【Linux】
|
2月前
|
Linux C语言 Windows
在Linux写自己的第一个程序“hello Linux”
在Linux写自己的第一个程序“hello Linux”
在Linux写自己的第一个程序“hello Linux”
|
6天前
|
机器学习/深度学习 缓存 监控
linux查看CPU、内存、网络、磁盘IO命令
`Linux`系统中,使用`top`命令查看CPU状态,要查看CPU详细信息,可利用`cat /proc/cpuinfo`相关命令。`free`命令用于查看内存使用情况。网络相关命令包括`ifconfig`(查看网卡状态)、`ifdown/ifup`(禁用/启用网卡)、`netstat`(列出网络连接,如`-tuln`组合)以及`nslookup`、`ping`、`telnet`、`traceroute`等。磁盘IO方面,`iostat`(如`-k -p ALL`)显示磁盘IO统计,`iotop`(如`-o -d 1`)则用于查看磁盘IO瓶颈。