Linux :理解编译的四个阶段
创始人
2024-05-30 03:46:06
0

目录

  • 一、了解编译
  • 二、认识编译的四个阶段
    • (一)预处理
    • (二)编译
    • (三)汇编
    • (四)链接
      • 1.静态链接
      • 2.动态链接
  • 三、分步编译
    • (一)创建.c文件
    • (二)预处理
    • (三)编译
    • (四)汇编
    • (五)链接
    • (六)运行
  • 四、合并编译

  在Windows的IDE中编写代码时,我们只需要点击按钮就可以完成程序的编译,从而生成可执行文件。但在Linux中,我们需要使用指令来进行程序的编译和运行,因此也就需要来了解一下从代码到可执行文件会经历什么。我们这里以Linux中的gcc编译器为例。

一、了解编译

 什么是编译?

把我们敲的代码变成可执行文件。

 什么是可执行文件?

就是可以直接运行的程序文件。例如Windows中的.exe文件。

 windows中如何编译?

在windows中我们使用IDE进行程序的编译和运行时仅需要鼠标点击几下就可以完成

 Linux中如何编译代码?

在Linux中我们使用的gcc来编译C语言代码,使用g++来编译C++代码,这两个是不可以混用的。

  我们都知道,在程序写好后,需要先进行编译,只有编译通过了,这个程序才可以尝试运行,如果编译都不能通过,谈何运行呢?

  而程序的编译大致分为四部分:

  • 预处理(预编译)
  • 编译
  • 汇编
  • 链接

  以上这四个阶段就是一个程序在整个编译阶段会经历的四步操作,接下来就让我们详细看一下这四步操作都在干什么。

二、认识编译的四个阶段

(一)预处理

  假设此时我们写了一个名叫mian.c的程序。这是编译的第一阶段,这个阶段会做什么?

  1. 宏替换
  2. 去注释
  3. 引入头文件

 什么是宏替换?

宏替换:将定义的宏直接用值替换掉

 什么是去注释?

去注释:把文件中所写的注释去掉

 什么是引入头文件?

我们在编写代码的过程中,不可避免地要使用库函数,因此会包含对应的头文件,头文件中存储的是库函数的函数声明。这一步就是把头文件中的包含的函数声明等内容复制到我们写的main.c程序中。这里需要注意,头文件中放的都是函数的声明,并不是定义,函数的定义在库中。也就是说,这里是把头文件中的函数声明搬进来了。

  这个阶段执行完成后,生成的文件本质还是一个C程序,因为它只是引入了一些函数声明,去掉了注释,进行了宏的替换。所以这一步并不会发现我们程序的错误,我们把这个新生成的文件称为 main.i 文件。

(二)编译

  编译阶段编译器会对main.i文件做什么?

  1. 语法语义纠错
  2. 把mian.i文件转换成汇编代码文件

  首先检查main.i文件中的语法语义有没有错,有错自然就会报错了。如果没有错,就会把我们的mian.i程序解释成汇编指令mian.s文件。

  经过这个阶段,mian.s文件就成为了汇编代码,不再是C代码。

(三)汇编

  汇编阶段会对main.s文件做什么?

  • 把汇编指令解释为二进制指令文件mian.o文件

  这一步会将会汇编指令mian.s文件解释成二进制指令文件,也就是电脑能够识别的指令文件。此时的main.o文件就是二进制文件。

(四)链接

  链接阶段会对main.o文件做什么?

  • 链接库文件或相关文件,生成可执行文件。

  生成main.o是不够的,此时的它还无法执行。因为我们在预处理阶段引入的仅仅是函数的声明,但是光有声明,没有定义,这也运行不了啊。

  因此在这个阶段,会把main.o文件和存储函数定义的库文件进行链接,让我们的程序运行函数时,可以找到函数的实现。从而生成可执行程序main文件。

  链接方式有两种:静态链接和动态链接,Linux中默认是动态链接。

1.静态链接

  生成可执行程序时,会把函数在库中的实现搬到我们的文件中,这样所有的函数声明和函数定义都在可执行文件中了。

  • 好处:运行时不需要依赖库文件,因为函数的定义和声明都被复制到我们的可执行文件中了。
  • 坏处:因为我们把函数的定义复制到了可执行文件中,因此生成的可执行程序比较庞大。如果多个程序使用了相同的库函数,那么运行的时候内存中会存在大量冗余代码

2.动态链接

  如果我们的程序中调用了库函数A,动态链接会把A函数定义在库文件中的位置记录下来,保存到可执行文件中,并不会把函数的具体的实现复制过来。

  当可执行程序运行时,动态库就会被加载到内存中,当可执行文件需要用到哪个函数的话,只需要根据记录在可执行文件中的位置,去内存中的动态库寻找即可。

  1. 好处:当多个程序都使用这个库的时候,只需要加载一个到内存中即可。这样代码冗余更小
  2. 坏处:运行程序时,动态库必须存在,不然去哪里找函数的实现。

三、分步编译

  • gcc -E main.c -o main.i:将main.c文件预处理成main.i文件
  • gcc -S main.i -o main.s:将main.i文件编译为汇编文件main.s
  • gcc -c main.s -o main.o:将main.s文件经过汇编处理,生成main.o文件
  • gcc mian.o -o mian:将main.o文件与库文件链接,生成可执行文件main

(一)创建.c文件

 注意:这里的-o是指定生成的文件名称。

创建main.c文件
写入main.c文件

(二)预处理

gcc -E main.c -o main.i

生成main.i文件

(三)编译

gcc -S main.i -o main.s

生成mian.s文件

(四)汇编

gcc -c main.s -o main.o

生成main.o文件

(五)链接

gcc mian.o -o mian

生成main文件

(六)运行

运行

四、合并编译

  按照上面的分步编译虽然可以达到我们的预期目标,但是比较麻烦,毕竟敲那么多指令也比较费事,因此推荐采用下面这样的合并编译。

  • gcc -E main.c -o main.i:将main.c文件处理到预处理阶段完毕
  • gcc -S main.c -o main.s:将main.c文件处理到编译阶段完毕
  • gcc -c main.c -o main.o:将main.c文件处理到汇编阶段完毕
  • gcc mian.c -o mian:将main.c文件处理到链接阶段完毕。

  上面这些指令可以提高我们的效率,因此通常直接使用第四条指令一步到位。

一步到位main

相关内容

热门资讯

北方长龙跌2.00%,成交额6... 7月9日,北方长龙盘中下跌2.00%,截至09:35,报83.17元/股,成交6764.12万元,换...
恒而达涨2.04%,成交额60... 7月9日,恒而达盘中上涨2.04%,截至09:36,报48.44元/股,成交6019.87万元,换手...
A100ETF易方达(1596... 7月9日,A100ETF易方达(159686)开盘涨0.19%,报1.055元。A100ETF易方达...
特发信息跌2.12%,成交额9... 7月9日,特发信息(维权)盘中下跌2.12%,截至09:36,报7.86元/股,成交9507.33万...
央企科技ETF(560170)... 7月9日,央企科技ETF(560170)开盘涨0.00%,报0.882元。央企科技ETF(56017...
泰祥股份涨2.04%,成交额8... 7月9日,泰祥股份盘中上涨2.04%,截至09:36,报26.06元/股,成交870.52万元,换手...
东华测试涨2.05%,成交额2... 7月9日,东华测试(维权)盘中上涨2.05%,截至09:36,报38.34元/股,成交2227.04...
金诚信涨2.06%,成交额2.... 7月9日,金诚信盘中上涨2.06%,截至09:36,报47.15元/股,成交2.65亿元,换手率0....
科创100ETF易方达(588... 7月9日,科创100ETF易方达(588210)开盘跌0.10%,报0.997元。科创100ETF易...
创业板综ETF华夏(15956... 7月9日,创业板综ETF华夏(159563)开盘涨0.22%,报1.389元。创业板综ETF华夏(1...