ChatGPT解决这个技术问题 Extra ChatGPT

我试图更好地理解差异。我在网上找到了很多解释,但它们倾向于抽象的差异而不是实际的含义。

我的大部分编程经验都是使用 CPython(动态、解释)和 Java(静态、编译)。但是,我知道还有其他类型的解释和编译语言。除了可执行文件可以从用编译语言编写的程序中分发之外,每种类型有什么优点/缺点吗?我经常听到人们争论解释语言可以交互使用,但我相信编译语言也可以有交互实现,对吗?

您为此比较选择了最差的语言。两者都是字节编译的。它们之间唯一真正的区别是 JITer,甚至 Python 也有部分区别(psyco)。
交互式编译语言的一个很好的例子是 Clojure - 一切都是完全编译的(首先编译到 JVM,然后通过 JIT 编译到本机代码)。然而,许多重新编译是动态发生的,并且开发通常在交互式 REPL shell 中完成,您可以在其中评估运行环境中所需的任何功能。
标准 ML 是另一种交互式编译语言;内置编译器也发出真正的本机机器代码。

M
Marie

编译语言是一种程序,一旦编译,就会在目标机器的指令中表达。例如,源代码中的加法“+”操作可以直接转换为机器代码中的“ADD”指令。

解释型语言是一种指令不直接由目标机器执行,而是由其他程序(通常用本机语言编写)读取和执行的语言。例如,解释器会在运行时识别相同的“+”操作,然后使用适当的参数调用自己的“add(a,b)”函数,然后执行机器代码“ADD”指令.

你可以用编译语言做任何你可以用解释语言做的事情,反之亦然——它们都是图灵完备的。然而,两者在实施和使用方面都有优点和缺点。

我将完全概括(纯粹主义者原谅我!)但是,粗略地说,这是编译语言的优点:

直接使用目标机器的本机代码,性能更快

在编译阶段应用非常强大的优化的机会

以下是解释语言的优点:

更容易实现(编写好的编译器非常困难!!)

无需运行编译阶段:可以“即时”直接执行代码

对于动态语言可以更方便

请注意,字节码编译等现代技术增加了一些额外的复杂性——这里发生的情况是编译器针对的是与底层硬件不同的“虚拟机”。这些虚拟机指令可以在稍后阶段再次编译以获得本机代码(例如,由 Java JVM JIT 编译器完成)。


@Kareem:JIT 编译器只执行 1) 和 2) 一次 - 之后它一直是本机代码。每次调用代码时,解释器都需要执行 1) 和 2)(可能很多次……)。因此,随着时间的推移,JIT 编译器会以很大的优势获胜。
是的,字节码在整个程序执行期间的某个时间点被转换为机器代码(与传统编译器的情况相反,在程序执行之前)。但是在整个程序执行期间,一段给定的代码可能会执行 1000 万次以上。它(可能)只从字节码编译一次到机器码。因此 JIT 的运行时开销很小,对于长时间运行的程序可以忽略不计。在 JIT 编译器完成其工作后,您将一直有效地运行纯机器代码。
这实际上是一种错误的二分法。语言本身并没有任何东西可以编译我们的解释。这只不过是一种普遍存在的误解。许多语言都有这两种实现,所有语言都可以有。
@mmachenry 这不是错误的二分法。 “编程语言”包括设计和实现。虽然从理论上讲,给定的语言定义既可以编译也可以解释,但在现实世界的实践中,实现上有很大差异。例如,还没有人解决如何有效地编译某些语言结构——这是一个开放的研究问题。
@mikera 确实如此。编译有好处,解释也有好处。仅仅因为编译器技术正在开发以改进某些语言的特性并不意味着我们可以说编译具有该特性的语言的好处。将语言和实现混为一谈会导致我们对为实现选择编译或解释产生错误的理解。例如,您的评论“[解释器] 可以更方便地使用动态语言”
佚名

语言本身既不编译也不解释,只有语言的特定实现才是。 Java 就是一个完美的例子。有一个基于字节码的平台(JVM)、一个本地编译器(gcj)和一个 Java 超集的解释器(bsh)。那么Java现在是什么?字节码编译、本机编译还是解释?

其他可以编译和解释的语言是 Scala、Haskell 或 Ocaml。这些语言中的每一种都有一个交互式解释器,以及一个字节码或本机机器码的编译器。

因此,通常按“编译”和“解释”对语言进行分类没有多大意义。


我同意。或者比方说:有本地编译器(创建供 CPU 吃的机器代码)和非本地编译器(创建标记化的东西,即中间代码,一些即时编译器在之前编译为机器代码(或在运行时 ONCE 期间),并且有“真正的”非编译器永远不会产生机器代码并且永远不会让 CPU 运行代码。后者是口译员。今天,在编译时直接生成机器(CPU)代码的本地编译器变得越来越少。 Delphi/Codegear 是最好的幸存者之一。
N
NealB

从以下方面开始思考:过去的爆炸

从前,很久很久以前,存在着计算解释器和编译器的土地。随之而来的是各种大惊小怪。当时的普遍看法是这样的:

解释器:快速开发(编辑和运行)。执行速度很慢,因为每条语句每次执行时都必须被解释为机器代码(想想这对于执行数千次的循环意味着什么)。

编译器:开发缓慢(编辑、编译、链接和运行。编译/链接步骤可能需要很长时间)。执行速度快。整个程序已经是本地机器代码。

解释程序和编译程序之间存在一个或两个数量级的运行时性能差异。其他区别点,例如代码的运行时可变性,也引起了人们的兴趣,但主要区别在于运行时性能问题。

今天,情况已经发展到这样一个程度,编译/解释的区别几乎无关紧要。许多编译语言调用不完全基于机器代码的运行时服务。此外,大多数解释型语言在执行之前都被“编译”成字节码。从执行速度的角度来看,字节码解释器可以非常有效并且可以与某些编译器生成的代码相媲美。

经典的区别是编译器生成本机机器代码,解释器读取源代码并使用某种运行时系统动态生成机器代码。今天剩下的经典解释器很少——几乎所有的解释器都编译成字节码(或其他一些半编译状态),然后在虚拟“机器”上运行。


C
Carl Smotricz

极端和简单的情况:

编译器将以目标机器的本机可执行格式生成二进制可执行文件。此二进制文件包含除系统库以外的所有必需资源;它无需进一步准备和处理即可运行,并且运行起来就像闪电一样,因为代码是目标机器上 CPU 的本机代码。

解释器将在循环中向用户显示提示,用户可以在其中输入语句或代码,并且在点击 RUN 或等效项时,解释器将检查、扫描、解析和解释性地执行每一行,直到程序运行到停止点或错误。因为每一行都是单独处理的,并且解释器不会从之前看到的行中“学习”任何东西,所以每次都需要为每一行将人类可读的语言转换为机器指令的工作,所以它很慢。从好的方面来说,用户可以通过各种方式检查他的程序并与之交互:更改变量、更改代码、在跟踪或调试模式下运行……等等。

有了这些,让我解释一下生活不再那么简单了。例如,

许多解释器会预编译他们给出的代码,这样翻译步骤就不必一次又一次地重复。

一些编译器不编译为特定于 CPU 的机器指令,而是编译为字节码,一种用于虚拟机器的人工机器代码。这使得编译后的程序更具可移植性,但在每个目标系统上都需要一个字节码解释器。

字节码解释器(我在这里看 Java)最近倾向于在执行之前重新编译它们为目标部分的 CPU 获得的字节码(称为 JIT)。为了节省时间,这通常只针对经常运行的代码(热点)进行。

一些看起来和行为都像解释器的系统(例如 Clojure)会立即编译它们获得的任何代码,但允许对程序环境进行交互式访问。这基本上是解释器以二进制编译的速度提供的便利。

一些编译器并不真正编译,它们只是预先消化和压缩代码。不久前我听说 Perl 就是这样工作的。所以有时编译器只是做了一些工作,其中大部分仍然是解释。

最后,这些天来,解释与编译是一种权衡,花费(一次)编译的时间通常会因更好的运行时性能而得到回报,但解释环境提供了更多的交互机会。编译与解释主要是关于“理解”程序的工作如何在不同进程之间划分的问题,而如今,随着语言和产品试图提供两全其美的方式,这条线有点模糊。


B
Bhavin Shah

来自http://www.quora.com/What-is-the-difference-between-compiled-and-interpreted-programming-languages

没有区别,因为“编译型编程语言”和“解释型编程语言”不是有意义的概念。任何编程语言,我的意思是任何编程语言,都可以被解释或编译。因此,解释和编译是实现技术,而不是语言的属性。解释是一种技术,另一个程序解释器代表正在解释的程序执行操作以运行它。如果你可以想象阅读一个程序并按照它所说的一步一步做,比如说在一张草稿纸上,那也正是解释器所做的。解释程序的一个常见原因是解释器相对容易编写。另一个原因是解释器可以监视程序在运行时尝试执行的操作,以强制执行策略,例如安全性。编译是一种技术,用一种语言(“源语言”)编写的程序被翻译成另一种语言(“目标语言”)的程序,希望与原始程序具有相同的含义。在进行翻译时,编译器通常也会尝试以使目标程序更快的方式转换程序(不改变其含义!)。编译程序的一个常见原因是,有一些很好的方法可以快速运行目标语言中的程序,而无需在此过程中解释源语言的开销。根据上面的定义,你可能已经猜到了,这两种实现技术并不是相互排斥的,甚至可能是互补的。传统上,编译器的目标语言是机器代码或类似的东西,它指的是特定计算机 CPU 可以理解的任意数量的编程语言。然后机器代码将“在金属上”运行(尽管如果仔细观察,可能会发现“金属”的工作方式很像解释器)。然而,今天,使用编译器生成要被解释的目标代码是很常见的——例如,Java 过去(有时仍然如此)就是这样工作的。有编译器将其他语言翻译成 JavaScript,然后通常在 Web 浏览器中运行,它可能会解释 JavaScript,或者将其编译为虚拟机或本机代码。我们还有机器代码解释器,可用于在另一种硬件上模拟一种硬件。或者,可以使用编译器生成目标代码,然后将其作为另一个编译器的源代码,该编译器甚至可以及时编译内存中的代码以使其运行,而这反过来又可以。 . .你明白了。有很多方法可以组合这些概念。


你能修正一下这句话吗:“有些编译器可以将其他语言翻译成 JavaScript,然后通常在 Web 浏览器中运行,它可能会解释 JavaScript,或者将其编译为虚拟机或本机代码。”
搞定了。另一个常见的错误是将语言的有用性归因于其现有的 API。
N
Niko Bellic

解释源代码相对于编译源代码的最大优势是可移植性。

如果您的源代码已编译,您需要为您希望程序运行的每种类型的处理器和/或平台编译不同的可执行文件(例如,一个用于 Windows x86,一个用于 Windows x64,一个用于 Linux x64,等等上)。此外,除非您的代码完全符合标准并且不使用任何特定于平台的函数/库,否则您实际上需要编写和维护多个代码库!

如果您的源代码被解释,您只需要编写一次,它就可以在任何平台上由适当的解释器解释和执行!它是便携式的!请注意,解释器本身是为特定平台编写和编译的可执行程序。

编译代码的一个优点是它对最终用户隐藏了源代码(可能是知识产权),因为您不是部署原始的人类可读的源代码,而是部署一个不起眼的二进制可执行文件。


在这个方面,java 不能被认为是一种“编译语言”,但它的编译阶段提供了编译的优势(类型检查、早期错误检测等),并生成可以在每个操作系统上运行的字节码,使用 Java提供的虚拟机。
M
Michael Borgwardt

编译器和解释器做同样的工作:将一种编程语言翻译成另一种编程语言,通常更接近硬件,通常是直接可执行的机器代码。

传统上,“编译”意味着这种翻译一次完成,由开发人员完成,生成的可执行文件分发给用户。纯示例:C++。编译通常需要很长时间并尝试进行大量昂贵的优化,以便生成的可执行文件运行得更快。最终用户没有自己编译东西的工具和知识,并且可执行文件通常必须在各种硬件上运行,因此您无法进行许多特定于硬件的优化。在开发过程中,单独的编译步骤意味着更长的反馈周期。

传统上,“解释”意味着当用户想要运行程序时,翻译“即时”发生。纯示例:普通 PHP。一个天真的解释器每次运行时都必须解析和翻译每段代码,这使得它非常慢。它不能进行复杂、昂贵的优化,因为它们所花费的时间比执行所节省的时间要长。但它可以充分利用它所运行的硬件的功能。缺少单独的编译步骤减少了开发过程中的反馈时间。

但是现在“编译与解释”不是一个非黑即白的问题,两者之间存在阴影。天真、简单的解释器几乎绝迹了。许多语言使用两步过程,将高级代码转换为与平台无关的字节码(解释起来要快得多)。然后你有“即时编译器”,每次程序运行最多编译一次代码,有时缓存结果,甚至智能地决定解释很少运行的代码,并对运行很多的代码进行强大的优化。在开发过程中,即使对于传统编译语言,调试器也能够在运行程序中切换代码。


但是,C++ 的编译模型继承自 C,在设计时没有考虑模板等特性。与其他任何因素相比,这种笨拙对 C++ 编译时间的影响要大得多 - 并使其成为一个糟糕的例子。
A
AGuyCalledGerald

首先,澄清一下,Java 没有像 C++ 那样完全静态编译和链接。它被编译成字节码,然后由 JVM 解释。 JVM 可以对本地机器语言进行即时编译,但不必这样做。

更重要的是:我认为交互性是主要的实际区别。由于所有内容都已解释,因此您可以提取一小段代码,针对当前环境状态进行解析和运行。因此,如果您已经执行了初始化变量的代码,那么您将可以访问该变量等。它确实适用于函数式样式等内容。

然而,解释的成本很高,尤其是当您拥有一个包含大量参考资料和上下文的大型系统时。根据定义,这是浪费的,因为相同的代码可能必须被解释和优化两次(尽管大多数运行时都有一些缓存和优化)。尽管如此,您还是需要支付运行时成本,并且通常需要运行时环境。您也不太可能看到复杂的过程间优化,因为目前它们的性能没有足够的交互性。

因此,对于不会发生太大变化的大型系统,以及对于某些语言,预编译和预链接所有内容更有意义,做所有可以做的优化。这最终得到了一个非常精简的运行时,该运行时已经针对目标机器进行了优化。

至于生成可执行文件,这与它无关,恕我直言。您通常可以从编译语言创建可执行文件。但是您也可以从解释语言创建可执行文件,除非解释器和运行时已经打包在可执行文件中并且对您隐藏。这意味着您通常仍然需要支付运行时成本(尽管我确信对于某些语言,有办法将所有内容转换为树可执行文件)。

我不同意所有语言都可以交互。某些语言,如 C,与机器和整个链接结构紧密相关,我不确定您是否可以构建一个有意义的成熟的交互式版本


并没有真正与“机器”联系在一起。 C 的语法和语义相当简单。实现 C 解释器应该不是特别困难,只是非常耗时(因为还必须实现标准库)。顺便说一句,Java 可以编译为本机机器代码(使用 gcj)。
@lunaryorn:我不同意 GCJ。 GCJ 只是给你一个基于可执行的环境。 “编译后的应用程序与 GCJ 运行时 libgcj 链接,它提供核心类库、垃圾收集器和字节码解释器”
GCJ 确实产生了本机机器代码,而不仅仅是具有嵌入式解释器和字节码的可执行环境。 libgcj 提供了一个字节码解释器来支持从本地代码到 Java 字节码的调用,而不是解释编译后的程序。如果 libgcj 没有提供字节码解释器,GCJ 将不符合 Java 规范。
@lunaryorn:啊。好的,我感谢您的澄清并纠正。我们主要在 Windows 环境中使用 Java,所以我多年来没有尝试过 gcj。
B
Buddhika Chathuranga

我猜这是计算机科学中最大的误解之一。因为解释和编译完全是两个不同的东西,我们不能这样比较。

编译是将一种语言翻译成另一种语言的过程。编译的类型很少。

编译 - 将高级语言翻译成机器/字节码(例如:C/C++/Java)

Transpiling - 将高级语言翻译成另一种高级语言(例如:TypeScript)

解释是实际执行程序的过程。这可能以几种不同的方式发生。

机器级解释——这种解释发生在编译成机器代码的代码上。指令由处理器直接解释。诸如 C/C++ 之类的编程语言会生成可由处理器执行的机器代码。所以处理器可以直接执行这些指令。

虚拟机级解释——这种解释发生在没有编译成机器级(处理器支持)代码,而是编译成一些中间级代码的代码上。该执行由另一个软件完成,该软件由处理器执行。此时实际上处理器看不到我们的应用程序。它只是执行虚拟机,它正在执行我们的应用程序。 Java、Python、C# 等编程语言生成字节码,可由虚拟解释器/机器执行。

因此,归根结底,我们必须了解的是,世界上所有的编程语言都应该在某个时候被解释。它可以由处理器(硬件)或虚拟机完成。

编译只是将我们编写的人类可理解的高级代码带入某些硬件/软件机器可理解的级别的过程。

这完全是两个不同的东西,我们无法比较。但是这个术语非常适合教初学者编程语言是如何工作的。

PS:像 Java 这样的一些编程语言有一种混合方法来做到这一点。首先,将高级代码编译成虚拟机可读的字节码。在运行中,称为 JIT 编译器的组件将字节码编译为机器码。具体来说,多次重复执行的代码行被翻译成机器语言,这使得解释过程更快。因为硬件处理器总是比虚拟解释器/处理器快得多。

How Java JIT compiler works


S
Steven Mohr

给出一个实际的答案相当困难,因为区别在于语言定义本身。可以为每种编译语言构建解释器,但不可能为每种解释语言构建编译器。这非常关乎语言的正式定义。所以大学里没人喜欢理论信息学的东西。


当然,您可以为解释语言构建编译器,但编译后的机器代码本身就是运行时的镜像。
不仅仅是运行时的镜像。例如,想象一下许多脚本语言中的 eval() 之类的结构:您实际上必须在生成的程序中包含 compiler,而不仅仅是运行时。
p
pacholik

Python Book © 2015 Imagine Publishing Ltd,通过第 10 页中提到的以下提示简单地区分了差异:

Python 等解释型语言是一种将源代码转换为机器代码,然后在每次程序运行时执行的语言。这与诸如 C 之类的编译语言不同,其中源代码只转换为机器代码一次——然后每次程序运行时都会执行生成的机器代码。


s
salehvm

编译是从用已编译的编程语言编写的代码创建可执行程序的过程。编译允许计算机运行和理解程序,而不需要用于创建它的编程软件。当一个程序被编译时,它通常是为一个特定的平台(例如 IBM 平台)编译的,该平台与 IBM 兼容的计算机一起工作,而不是其他平台(例如 Apple 平台)。第一个编译器是由 Grace Hopper 在哈佛 Mark I 计算机上开发的。今天,大多数高级语言都将包含它们自己的编译器或提供可用于编译程序的工具包。与 Java 一起使用的编译器的一个很好的例子是 Eclipse,与 C 和 C++ 一起使用的编译器的一个例子是 gcc 命令。根据程序的大小,编译应该需要几秒钟或几分钟,如果在编译时没有遇到错误,则会创建一个可执行文件。检查此信息


u
uliwitness

简短(不精确)的定义:

编译语言:整个程序一次被翻译成机器码,然后机器码由CPU运行。

解释性语言:程序是逐行读取的,只要读取一行,CPU就会执行该行的机器指令。

但实际上,如今很少有语言是纯粹编译或纯粹解释的,它通常是混合的。有关图片的更详细说明,请参阅此线程:

What is the difference between compilation and interpretation?

或者我后来的博文:

https://orangejuiceliberationfront.com/the-difference-between-compiler-and-interpreter/