程序员的自我修养笔记 2

编译的基本流程

构建:编译和链接合并到一起的过程。

整个编译的过程可以分为4个阶段:

  • 预处理:主要是处理#符号后面的内容,比如展开宏定义和处理ifndef等;还包括删除掉所有的注释等。还有一个重要的步骤,如果涉及到头文件包含,那么会把包含头文件插入到相应的#include的位置。
  • 编译:主要是词法分析、语法分析、语义分析和优化相应的代码产生汇编语言等。
  • 汇编:把汇编代码转换成机器码。到这一步的时候,就可以生成*.o的目标文件了。
  • 链接:把目标文件最后生成可执行代码。

整个编译的过程流程图:
在这里插入图片描述

关于上述编译的几个过程:

  • 词法分析:把源代码的关键词等转换成相应的记号。
  • 语法分析:把此法分析的记号转换成语法树。
  • 语义分析:判断词法树的操作是否是有意义的,比如指针和浮点数做乘法运算是否有意义,这里涉及到语义类型:
    • 静态语义:编译期间可以确定的,比如类型转换、声明匹配等。
    • 动态语义:运行期间才可以确定的,比如输入0作为除数是否合法的判定

在完成语义分析后,编译器生成中间代码,这是语法树的一个顺序表示,该代码与平台无关。生成中间代码之前的步骤是编译前端,之后的是编译后端。

链接

强烈推荐这一系列的博客https://segmentfault.com/a/1190000016417397

编译后端主要包括两个部分:

  • 代码生成器:把中间代码转换到目标机器代码,但是这里可能有变量或者函数的在其他文件中,无法确定它们的绝对地址。
  • 目标代码优化器:优化代码的,比如-O2优化等。

在程序中,如果涉及到函数跳转或者变量引用的时候,编译器需要知道引用的函数或者变量的实际地址,在现在编译器中,“符号(Symbol)”用来表示一个地址,它可以是子程序(函数)或者变量的地址。

现在软件开发中,都是分模块进行的,我们可以把不同的模块分别进行编译处理,最终这些编译的模块需要组成一个单一的完整的程序,这个组合拼接的过程就是链接。拼接组合的问题可以归结为模块间的通信问题,以C/C++为例,模块间的函数调用和模块间的变量访问,都需要知道相应的绝对地址。

在之前的编译过程中,如果遇到某个变量的使用,只要编译器找到了变量的声明,那么就认为是编译通过了;具体寻找该变量的定义的过程,是由编译器来做的。

在链接的过程中,主要分为3个步骤,更详细的理解,可以参考这一系列的博客

  • 地址和空间分配(Address and Storage Allocation):对变量函数等分配有关的地址和空间
  • 符号决议(Symbol Resolution):确保所有目标文件中的符号引用都有唯一的定义
  • 重定位(Relocation):在把目标文件拼装成可执行文件的过程中,不断修正函数和变量绝对地址的过程。

静态链接的基本概念:链接器将使用到的目标文件集合进行拼装,拼装之后就生成了可执行文件。拼装目标文件时,连接器直接采用复制的已有目标文件的方式,所以静态链接可能存在执行文件过大的问题。windows下,静态链接时.lib后缀的;Linux下静态链接是.a后缀的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值