编译原理什么是规范句型
① 编译原理
C语言编译过程详解
C语言的编译链接过程是要把我们编写的一个C程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。过程图解如下:
从图上可以看到,整个代码的编译过程分为编译和链接两个过程,编译对应图中的大括号括起的部分,其余则为链接过程。
一、编译过程
编译过程又可以分成两个阶段:编译和汇编。
1、编译
编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,源文件的编译过程包含两个主要阶段:
第一个阶段是预处理阶段,在正式的编译阶段之前进行。预处理阶段将根据已放置在文件中的预处理指令来修改源文件的内容。如#include指令就是一个预处理指令,它把头文件的内容添加到.cpp文件中。这个在编译之前修改源文件的方式提供了很大的灵活性,以适应不同的计算机和操作系统环境的限制。一个环境需要的代码跟另一个环境所需的代码可能有所不同,因为可用的硬件或操作系统是不同的。在许多情况下,可以把用于不同环境的代码放在同一个文件中,再在预处理阶段修改代码,使之适应当前的环境。
主要是以下几方面的处理:
(1)宏定义指令,如 #define a b。
对于这种伪指令,预编译所要做的是将程序中的所有a用b替换,但作为字符串常量的 a则不被替换。还有 #undef,则将取消对某个宏的定义,使以后该串的出现不再被替换。
(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉
(3) 头文件包含指令,如#include "FileName"或者#include <FileName>等。
在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。包含到C源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。在程序中#include它们要使用尖括号(<>)。另外开发人员也可以定义自己的头文件,这些文件一般与C源程序放在同一目录下,此时在#include中要用双引号("")。
(4)特殊符号,预编译程序可以识别一些特殊的符号。
例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。
预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。
第二个阶段编译、优化阶段。经过预编译得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,{,}, +,-,*,\等等。
编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。
优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。优化一部分是对中间代码的优化。这种优化不依赖于具体的计算机。另一种优化则主要针对目标代码的生成而进行的。
对于前一种优化,主要的工作是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)、复写传播,以及无用赋值的删除,等等。
后一种类型的优化同机器的硬件结构密切相关,最主要的是考虑是如何充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对于内存的访问次数。另外,如何根据机器硬件执行指令的特点(如流水线、RISC、CISC、VLIW等)而对指令进行一些调整使目标代码比较短,执行的效率比较高,也是一个重要的研究课题。
2、汇编
汇编实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。目标文件由段组成。通常一个目标文件中至少有两个段:
代码段:该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。
数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。
UNIX环境下主要有三种类型的目标文件:
(1)可重定位文件
其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。
(2)共享的目标文件
这种文件存放了适合于在两种上下文里链接的代码和数据。
第一种是链接程序可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个 目标文件;
第二种是动态链接程序将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象。
(3)可执行文件
它包含了一个可以被操作系统创建一个进程来执行之的文件。汇编程序生成的实际上是第一种类型的目标文件。对于后两种还需要其他的一些处理方能得到,这个就是链接程序的工作了。
二、链接过程
由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。
例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。
链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:
(1)静态链接
在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
(2) 动态链接
在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。
我们在linux使用的gcc编译器便是把以上的几个过程进行捆绑,使用户只使用一次命令就把编译工作完成,这的确方便了编译工作,但对于初学者了解编译过程就很不利了,下图便是gcc代理的编译过程:
从上图可以看到:
预编译
将.c 文件转化成 .i文件
使用的gcc命令是:gcc –E
对应于预处理命令cpp
编译
将.c/.h文件转换成.s文件
使用的gcc命令是:gcc –S
对应于编译命令 cc –S
汇编
将.s 文件转化成 .o文件
使用的gcc 命令是:gcc –c
对应于汇编命令是 as
链接
将.o文件转化成可执行程序
使用的gcc 命令是: gcc
对应于链接命令是 ld
总结起来编译过程就上面的四个过程:预编译、编译、汇编、链接。了解这四个过程中所做的工作,对我们理解头文件、库等的工作过程是有帮助的,而且清楚的了解编译链接过程还对我们在编程时定位错误,以及编程时尽量调动编译器的检测错误会有很大的帮助的。
② 什么是(文法的)规范推导(编译原理))
规范推导:最右推导
最右推导、最左推导、规范推导、规范句型
对于文法:G[S]:S → aAS | a
A → SbA | SS | ba
最右推导:S=> aA S =>a A a=>aSb A a
=>a S bbaa=>aabbaa(每次只推导 最右边 的非终结符,直到推导完毕)
(得到的句型为 规范句型 )
最左推导: S=>a A S=>a S bAS=>aab A S
=>aabba S =>aabbaa(与最右推导类比理解)
③ 编译原理-句型、句子、短语、直接短语、句柄、素短语、最左素短语
在进行语法分析的时候,有时候会对这些词语的概念不清晰,这里我们就详细归纳总结一下。
可以看出这个里面,最需要理解的概念就是短语,其他大部分概念都是在短语基础上延伸的,从概念上可以看出:
假设有一个文法
针对文法的一个特定句型 (Sd(T)db) , 其推导过程如下:
这个句型 (Sd(T)db) 对应的 CFG 分析树如下:
那个这个句型 (Sd(T)db) 有多少个短语呢?
还记得短语的定义么, S ⇒* αβδ , αβδ 代表句型就是这里的 (Sd(T)db) 。
因此这个句型 (Sd(T)db) :
算法非常简单,就是通过分析树的后序遍历,先将子树的叶节点从左到右排合并成字符串(即一个短语),然后用它代表子树的根节点的值,再和与子树根节点同一层节点值合并,得到新的短语。就这样从分析树的最底层,一路合并到分析树的根节点,就能得到所有的短语了。
通过递归的方法,获取短语列表 phraseList , 直接短语列表 directPhraseList 和 素短语列表 plainPhraseList 。
运行结果:
④ 在编译原理中,语法规则和词法规则有什么不同..
通俗的说,
规则主要识别单词
语法主要识别多个单词组成的句子
⑤ 规约的编译原理
推导的逆过程称为规约。规约就是选择一个文法规则:X→ABC,依次从栈顶弹出C、B、A,再将X压进栈。规范规约是文法中句子的一个最右推导的逆过程,而最左推导对应的是最右规约 。
另外在程序设计中的规约:∏和∏'是两个判定性问题,如果存在一个确定性算法A使得对于一个∏的实例I,A可以将I在多项式时间里转换成∏'的实例P,使得I得到肯定的回答,当且仅当I'得到肯定回答,则称∏在多项式时间里规约到∏',记为∏∝poly∏'.
⑥ 请问规范规约是什么意思(这个词应该是用在计算机编译原理中)
在编译原理中,规范规约是编译程序中语法分析(自下而上分析)阶段的,在此阶段中处理文法和句子。规范规约是文法中句子的一个最右推导的逆过程。
如果你是没学过编译原理的,这个具体要说意思的话,太抽象。你只要知道编译程序的工作是从输入源程序开始到输出目标程序为止的整个过程,而这个过程可分为五个阶段:词法分析、语法分析、语义分析与中间代码产生、优化、目标代码生成。规范规约就是语法分析中用到的,为后面的步骤做准备。
⑦ 有关编译原理
⑴拓广文法 1 分
G[S ′ ]: S ′→ S ⑴
S → SaA ⑵ S → a ⑶ A → AbS ⑷ A → b ⑸
该文法的以 LR(0) 项目集为状态的识别规范句型活前缀的 DFA :
⑵ 该文法的 LR(0) 分析表:
状态 ACTION GOTO
a b # S A
0 S 2 1
1 S 3 acc
2 r 3 r 3 r 3
3 S 5 4
4 r 2 r 2 /S 6 r 2
5 r 5 r 5 r 5
6 S 2 7
7 r 4 /S 3 r 4 r 4
⑶ LR(0) 文法:该文法的以 LR(0) 项目集为状态的识别规范句型活前缀的 DFA 中没有冲突状态。
该文法不是 LR(0) 文法
因为存在冲突状态: I 4 和 I 7
⑷ SLR(1) 文法:该文法的以 LR(0) 项目集为状态的识别规范句型活前缀的 DFA 中有冲突状态,冲突可用 FOLLOW 集解决。
该文法不是 SLR(1) 文法。
因为 FOLLOW(S)={a,b,#} ,所以无法解决冲突
⑧ 【编译原理】第二章:语言和文法
上述文法 表示,该文法由终结符集合 ,非终结符集合 ,产生式集合 ,以及开始符号 构成。
而产生式 表示,一个表达式(Expression) ,可以由一个标识符(Identifier) 、或者两个表达式由加号 或乘号 连接、或者另一个表达式用括号包裹( )构成。
约定 :在不引起歧义的情况下,可以只写产生式。如以上文法可以简写为:
产生式
可以简写为:
如上例中,
可以简写为:
给定文法 ,如果有 ,那么可以将符号串 重写 为 ,记作 ,这个过程称为 推导 。
如上例中, 可以推导出 或 或 等等。
如果 ,
可以记作 ,则称为 经过n步推导出 ,记作 。
推导的反过程称为 归约 。
如果 ,则称 是 的一个 句型(sentential form )。
由文法 的开始符号 推导出的所有句子构成的集合称为 文法G生成的语言 ,记作 。
即:
例
文法
表示什么呢?
代表小写字母;
代表数字;
表示若干个字母和数字构成的字符串;
说明 是一个字母、或者是字母开头的字符串。
那么这个文法表示的即是,以字母开头的、非空的字符串,即标识符的构成方式。
并、连接、幂、克林闭包、正闭包。
如上例表示为:
中必须包含一个 非终结符 。
产生式一般形式:
即上式中只有当上下文满足 与 时,才能进行从 到 的推导。
上下文有关文法不包含空产生式( )。
产生式的一般形式:
即产生式左边都是非终结符。
右线性文法 :
左线性文法 :
以上都成为正则文法。
即产生式的右侧只能有一个终结符,且所有终结符只能在同一侧。
例:(右线性文法)
以上文法满足右线性文法。
以上文法生成一个以字母开头的字母数字串(标识符)。
以上文法等价于 上下文无关文法 :
正则文法能描述程序设计语言中的多数单词。
正则文法能描述程序设计语言中的多数单词,但不能表示句子构造,所以用到最多的是CFG。
根节点 表示文法开始符号S;
内部节点 表示对产生式 的应用;该节点的标号是产生式左部,子节点从左到右表示了产生式的右部;
叶节点 (又称边缘)既可以是非终结符也可以是终结符。
给定一个句型,其分析树的每一棵子树的边缘称为该句型的一个 短语 。
如果子树高度为2,那么这棵子树的边缘称为该句型的一个 直接短语 。
直接短语一定是某产生式的右部,但反之不一定。
如果一个文法可以为某个句子生成 多棵分析树 ,则称这个文法是 二义性的 。
二义性原因:多个if只有一个else;
消岐规则:每个else只与最近的if匹配。
⑨ 锘虹路缂栬疟铡熺悊
娣卞叆鎺㈢储缂栬疟铡熺悊锛氢粠锘虹鍒伴珮绾цВ鏋
涓銆佺紪璇戠▼搴忕殑濂ョ
缂栬疟鍣锛岃繖搴ч氩线链哄櫒璇瑷镄勬ˉ姊侊纴灏嗘簮浠g爜镄勯瓟娉曡浆鍖栦负链哄櫒鑳界悊瑙g殑鎸囦护銆傚畠镄勬梾绋嫔垎涓哄叚姝ワ细璇嶆硶鍒嗘瀽锛埚皢婧愪唬镰佸垎鍓蹭负涓涓涓鍙璇嗗埆镄勫崟鍏冿级銆佽娉曞垎鏋愶纸瑙f瀽浠g爜缁撴瀯锛夈佽涔夊垎鏋愶纸璧嬩篑姣忎釜绗﹀彿镒忎箟锛夈佷腑闂翠唬镰佺敓鎴愶纸涓哄悗缁浼桦寲锅氩嗳澶囷级銆佷唬镰佷紭鍖栵纸鎻愬崌鏁堢巼锛夊拰鐩镙囦唬镰佺敓鎴愶纸鐢熸垚链缁埚彲镓ц屾枃浠讹级銆傜紪璇戣繃绋嫔阀濡栾繍鐢ㄨ〃镙肩$悊锛屽墠绔璁捐℃椂鐩镙囨満镞犲叧锛岃屽悗绔璁捐″垯绱у瘑缁戝畾鐩镙囧钩鍙扮壒镐с
浜屻佽В閲婄▼搴忎笌缂栬疟绋嫔簭镄勫樊寮
涓庣紪璇戠▼搴忎笉钖岋纴瑙i喷鍣ㄩ愯屾墽琛屾簮浠g爜锛屼笉鐢熸垚鍙镓ц屾枃浠讹纴杩欎娇寰楄В閲婄▼搴忚槠铹舵槗浜庤皟璇曪纴浣嗛熷害杈冩参涓斿崰鐢ㄥ唴瀛樿缉澶с
涓夈佽娉曚笌鏂囨硶镄勬ˉ姊
璇瑷镄勮掴锲剧敱璇娉曞拰璇涔夊叡钖屾瀯寤恒备笂涓嬫枃镞犲叧鏂囨硶锛屽傚悓璇瑷镄勯氱敤璇娉曡勫垯锛屾槸鎻忚堪鍜岀悊瑙h瑷缁撴瀯镄勫叧阌宸ュ叿銆
锲涖佺粓缁撶︿笌闱炵粓缁撶︾殑瀵嗙爜
缁堢粨绗︼纴濡傚悓璇瑷镄勫熀链鍏幂礌锛岄潪缁堢粨绗﹀垯鏄鐢辩粓缁撶﹀拰鏂囨硶瑙勫垯缁勫悎钥屾垚镄勬娊璞℃傚康锛屽叡钖屾瀯鎴愪简璇瑷镄勫熀鐭炽
浜斻丒BNF锛氭墿灞旷殑璇娉曟弿杩扮
EBNF锛圗xtended Backus-Naur Form锛夋槸涓绉嶅己澶х殑绗﹀彿琛ㄧず娉曪纴鐢ㄤ簬娓呮榈瀹氢箟澶嶆潅璇瑷缁撴瀯锛屾棤璁烘槸绠鍗旷被鍨嬭缮鏄镊瀹氢箟绫诲瀷锛岄兘鍙阃氲繃瀹幂簿鍑嗗畾涔夈
鍏銆佹帰绱㈣瑷镄勭﹀彿涓栫晫
阃氲繃瀛楁瘝琛▄0, 1}锛屾垜浠鍙浠ユ瀯阃犲嚭濡00銆10杩欐牱镄勭﹀彿涓层备覆杩炴帴銆佸箓杩愮畻鍜岄泦钖堣繍绠楋纴濡侫={a, b}脳B={c, d} = {ac, ad, bc, bd}锛屽𪾢绀轰简绗﹀彿涓茬殑涓板瘜镐с傞棴鍖呮傚康鎻绀轰简镓链夋湁闄愰暱涓茬殑闆嗗悎鐗规с
涓冦佹枃娉旷殑鏋勯犱笌瑙f瀽
鏂囨硶鐢遍潪缁堢粨绗﹂泦銆佺粓缁撶﹂泦銆佽勫垯闆嗗拰璇嗗埆绗︾粍鎴愶纴濡俛->b锛屾枃娉曚功鍐欎负G[S]銆傛帹瀵间笌瑙勭害灞旷ず浜呜瑷鏋勯犵殑阃昏緫锛屽彞鍨嫔拰璇瑷鍒欐槸鏂囨硶浣灭敤镄勪綋鐜帮纴涔斿嗘柉锘哄洓鍨嬫枃娉曞𪾢绀轰简阃掑綊鍜屼笂涓嬫枃鐩稿叧镐х殑涓嶅悓灞傛°
鍏銆佽娉曟爲锛氲瑷镄勭粨鏋勪箣缇
璇娉曟爲鐘瑰傜紪璇戠殑钃濆浘锛屾疮涓鑺傜偣镙囱颁负V绗﹀彿锛屼粠镙硅妭镣笋鍑哄彂锛岄伒寰鐗瑰畾瑙勫垯锛岀洿瑙傛彮绀哄彞鍨嬫帹瀵肩殑缁撴瀯銆
涔濄佽勮寖鎺ㄥ间笌鍙ュ瀷鍒嗘瀽
瑙勮寖鎺ㄥ肩‘淇濊В鏋愯繃绋嬬殑鍞涓镐э纴娑堥櫎浜屼箟镐э纴钥屽彞鍨嫔垎鏋愬垯阃氲繃镊涓婅屼笅鎴栬嚜涓嬭屼笂镄勬柟娉曪纴楠岃瘉绗﹀彿涓叉槸钖︾﹀悎鏂囨硶銆
鍗併佺Щ杩-褰掔害鍒嗘瀽涓庝紭鍏埚垎鏋愭硶
绉昏繘-褰掔害鍒嗘瀽灏呜緭鍏ラ愪釜瑙f瀽锛岀畻绗︿紭鍏埚垎鏋愬垯镙规嵁杩愮畻绗︿紭鍏堢骇鍐冲畾镎崭綔椤哄簭銆备笁绉崭紭鍏埚叧绯诲畾涔変简鍒嗘瀽镄勭簿缁嗘ラわ纴浠庣亩鍗曚紭鍏埚埌绠楃︿紭鍏堬纴鏁堢巼鍜岄傜敤锣冨洿钖勫纾銆
鍗佷竴銆丩R鍒嗘瀽鍣锛氲В鏋愮殑寮哄ぇ宸ュ叿
LR鍒嗘瀽鍣ㄦ槸瑙f瀽澶嶆潅鏂囨硶镄勫己澶ф﹀櫒锛屽畠阃氲繃ACTION琛ㄥ拰GOTO琛锛屼互鍙婃枃娉旷﹀彿鍜岀姸镐佺殑宸у欑$悊锛岀‘淇濊В鏋愮殑楂樻晥鍜屽嗳纭镐с
鍗佷簩銆佹爤鍦ㄨВ鏋愪腑镄勮掕壊
镙埚湪褰掔害銆佹帴鍙楀拰鎶ラ敊杩囩▼涓镓婕斿叧阌瑙掕壊锛屽綊绾︽椂璋冩暣鐘舵侊纴鎺ュ弹镞剁‘璁ゅ紑濮嬶纴阌栾镞跺垯鍙戝嚭璀﹀憡銆侺R鍒嗘瀽鍣ㄧ殑鍏抽敭鍦ㄤ簬鍒嗘瀽琛ㄧ殑鏋勫缓锛屽喅瀹氢简瑙f瀽鍣ㄧ殑镐ц兘鍜屾g‘镐с
鍗佷笁銆丩R(0)鍒嗘瀽镄勭簿濡欎箣澶
娲诲墠缂DFA镄勬瀯寤猴纴阃氲繃姝h勮〃杈惧纺鍜岄”鐩闆呜勮寖镞忥纴鎻绀轰简LR(0)鍒嗘瀽镄勬繁灞傞昏緫锛屽畠鍦ㄧ亩鍖栧啿绐佸勭悊镄勫悓镞讹纴鍏奸【浜嗗瓨鍌ㄦ晥鐜囧拰瑙f瀽鑳藉姏銆
缂栬疟铡熺悊镄勬梾绋嬫繁鍏ヨ屼赴瀵岋纴姣忎竴鐜鑺傞兘濡傚悓璇瑷镄勬瀯阃犱箰璋憋纴浜ょ粐鍑鸿$畻链虹戝︾殑浜ゅ搷涔愮珷銆备粠锘虹镄勮勫垯瑙f瀽锛屽埌楂樼骇镄勫垎鏋愭柟娉曪纴姣忎竴绔犻兘涓虹悊瑙d唬镰佽儗钖庣殑阃昏緫鎻愪緵浜嗗叧阌镄勬ˉ姊併
⑩ C语言编译原理是什么
编译共分为四个阶段:预处理阶段、编译阶段、汇编阶段、链接阶段。
1、预处理阶段:
主要工作是将头文件插入到所写的代码中,生成扩展名为“.i”的文件替换原来的扩展名为“.c”的文件,但是原来的文件仍然保留,只是执行过程中的实际文件发生了改变。(这里所说的替换并不是指原来的文件被删除)
2、汇编阶段:
插入汇编语言程序,将代码翻译成汇编语言。编译器首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,编译器把代码翻译成汇编语言,同时将扩展名为“.i”的文件翻译成扩展名为“.s”的文件。
3、编译阶段:
将汇编语言翻译成机器语言指令,并将指令打包封存成可重定位目标程序的格式,将扩展名为“.s”的文件翻译成扩展名为“.o”的二进制文件。
4、链接阶段:
在示例代码中,改代码文件调用了标准库中printf函数。而printf函数的实际存储位置是一个单独编译的目标文件(编译的结果也是扩展名为“.o”的文件),所以此时主函数调用的时候,需要将该文件(即printf函数所在的编译文件)与hello
world文件整合到一起,此时链接器就可以大显神通了,将两个文件合并后生成一个可执行目标文件。