程序的编译与解释有什么区别?
首先我们来看看解释器和编译器之间的关系。从本质上来讲所有程序都是解释执行的,除非你的程序直接被“硅编译”成电路或者其他什么机器。但是即使那样,我还是可以说宇宙就是它的解释器。
“处理器”就是机器代码的解释器。处理器的取码,解码,执行的流水线,跟高级语言的解释器非常类似。通常所谓的“解释语言”在处理器的基础上加了一层:处理器执行解释器的机器代码,解释器再来执行源代码(或者字节码)的数据结构。所以纯粹的“解释语言”(比如我的博文《怎样写一个解释器》里面实现的那个)一般都经过了两层或者更多的解释器。
"编译"的目的就是去掉中间的那层解释器,把源程序翻译成机器代码,然后让处理器直接解释执行这些机器代码。这就是为什么“编译语言”一般要快一些,因为少了一层“解释开销”。由于代码被翻译成了最下层解释器(处理器)需要的格式,所以代码不再依赖中间的解释器。
有时候这种中间的“解释开销”是不能完全消除的,或者有的语言实现只选择去掉其中一部分。
“处理器”就是机器代码的解释器。处理器的取码,解码,执行的流水线,跟高级语言的解释器非常类似。通常所谓的“解释语言”在处理器的基础上加了一层:处理器执行解释器的机器代码,解释器再来执行源代码(或者字节码)的数据结构。所以纯粹的“解释语言”(比如我的博文《怎样写一个解释器》里面实现的那个)一般都经过了两层或者更多的解释器。
"编译"的目的就是去掉中间的那层解释器,把源程序翻译成机器代码,然后让处理器直接解释执行这些机器代码。这就是为什么“编译语言”一般要快一些,因为少了一层“解释开销”。由于代码被翻译成了最下层解释器(处理器)需要的格式,所以代码不再依赖中间的解释器。
有时候这种中间的“解释开销”是不能完全消除的,或者有的语言实现只选择去掉其中一部分。
实际上大部分现代的“解释型语言”(比如 Python)都进行某种程度的编译,比如编译成字节码,然后解释执行这些字节码。编译成字节码可以去掉反复遍历语法树的那部分“解释开销”,带来解释器性能的提升,但是它没有完全的去掉解释开销。
所以“编译型”和“解释型”语言并没有明确的界限,通常所谓的“解释器”也可以进行一部分编译工作。“编译”和“解释”各自是有意义的,但是讨论一个语言是“编译型”还是“解释型”其实是没有多大意义的。我们应该讨论的问题是,一个语言实现的“解释开销”有多大。
解释器和编译器的关系,可以用 Futamura 提出的,由 Neil Jones 等发扬广大的概念 partial evaluation 来理解。请参考这本书:《Partial Evaluation》。
所以“编译型”和“解释型”语言并没有明确的界限,通常所谓的“解释器”也可以进行一部分编译工作。“编译”和“解释”各自是有意义的,但是讨论一个语言是“编译型”还是“解释型”其实是没有多大意义的。我们应该讨论的问题是,一个语言实现的“解释开销”有多大。
解释器和编译器的关系,可以用 Futamura 提出的,由 Neil Jones 等发扬广大的概念 partial evaluation 来理解。请参考这本书:《Partial Evaluation》。
------------------------------------------------------------------------------------------------------------------------------------------
@王垠 所说的编译型语言和解释型语言的本质都是解释执行的,虽然没有什么错误,但是感觉有些像是诡辩。编译型和解释型的语言之所以可以说相同,是因为这些语言从文本形式的
代码到最终产生的动作,所经历的过程是一样的。
一种高级编程语言,从源代码开始,一直到被执行生成相应的动作,大约经历了这几个步骤:
编译 执行
源代码====>(中间表示形式====>)基本操作序列====>生成最终动作
编译型和解释型语言的不同指出只是在于,这些过程发生的时机不一样。
编译型语言的代表是C,源代码被编译之后生成中间文件(.o和.obj),然后用连接器和汇编器生成机器码,也就是一系列基本操作的序列,机器码最后被执行生成最终动作。解释型的语言以Ruby为例,也经历了这些步骤,不同的是,C语言会把那些从源代码“变”来的基本操作序列(保存)起来,而Ruby直接将这些生成的基本操作序列(Ruby虚拟机)指令丢给Ruby虚拟机执行然后产生动作了。
所以我们看到的现象是,编译型语言要先编译再运行,而解释性语言直接“运行”源代码。
一种高级编程语言,从源代码开始,一直到被执行生成相应的动作,大约经历了这几个步骤:
编译 执行
源代码====>(中间表示形式====>)基本操作序列====>生成最终动作
编译型和解释型语言的不同指出只是在于,这些过程发生的时机不一样。
编译型语言的代表是C,源代码被编译之后生成中间文件(.o和.obj),然后用连接器和汇编器生成机器码,也就是一系列基本操作的序列,机器码最后被执行生成最终动作。解释型的语言以Ruby为例,也经历了这些步骤,不同的是,C语言会把那些从源代码“变”来的基本操作序列(保存)起来,而Ruby直接将这些生成的基本操作序列(Ruby虚拟机)指令丢给Ruby虚拟机执行然后产生动作了。
所以我们看到的现象是,编译型语言要先编译再运行,而解释性语言直接“运行”源代码。
除了BASIC这样特别早期的解释型语言,是直接解释执行,现在的解释型语言都采取将代码编译为某种特定的虚拟机代码或者机器码的形式,然后再执行那些编译好的代码。BASIC这种直接解释的,我们可以将他的基本操作序列理解为直接执行基本操作的那些函数。
现在关于解释和编译的界限也不是特别清晰了。
∙ Java需要预先把代码编译成虚拟机指令的,然后在运行这些虚拟机指令,有的教科书上会成为混合型或者半编译型。
∙ 像Python和lua这样就更不好分了,可以直接解释源代码运行,也可以编译为虚拟机指令然后再运行。
∙ php编译之后的结果可以被Web Server缓存起来,甚至还可以先被翻译为C++,然后再编译。
∙ .NET 的CLR运行时是Windows的组成部分,编译好的.NET 系列语言的代码直接生成可执行文件,然后被“直接”执行,看起来跟C没有什么太大的差别。
∙ JavaScript可以被V8引擎编译为机器码然后执行,如果在node.js下,这个编译结果被缓存起来了,你说这跟编译好再执行的C有什么区别?源程序能直接执行吗
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论