编译型语言与解释型语言

编译型语言与解释型语言

首先要说明,编译型语言与解释型语言这种分类方法是不科学的,或者说已经过时了,但是这种称呼大抵还是能够让人明白我们将要讨论的是什么东西。

文中所列参考是笔者认为比较有帮助的一些扩展阅读内容。

首先贴一个很形象的比喻,来自知乎@孛尔只斤南丁:

假设厂里来了两个新工人,一个叫编译,另一个叫解释。厂长(程序员)给他们安排了一项任务(需求),并发放了操作说明(源代码)。

编译这名工人的做法是先完整的看一遍操作说明,遇到错别字或者不明白的地方,就去问厂长,直到操作说明最终成为一个没有错别字且他自己完全能够理解的东西。然后他把操作说明的内容理解消化(编译),并且变成记忆(可执行程序)。之后每次需要完成任务的时候就靠自己的理解和记忆去执行,不再需要操作说明。

我们再看解释这个工人。他拿到操作说明二话不说直接上手,读一条,操作一步,再读一条,操作下一步,如此重复。就算是操作说明中有错别字或者他看不懂的地方,在没有读到那一条之前他是不知道的,也不影响他进行前面的操作,等真的读到错别字或者不能理解的条目再去问厂长。而且不管他执行这个任务执行了多少次,每次都是需要看着操作说明一步一步执行。

那这两个工人谁好谁坏呢?难说。

如果给他们安排的任务以后要重复很多次,而且步骤繁多,但是相对稳定不需要频繁调整,那么编译工人的工作效率可能会更高一些。因为任务相对稳定不需要调整,所以他只要第一次把不明白的地方跟厂长问清楚,自己理解消化记住了,以后的执行都是他自己内化理解的东西,做起来很快。

如果任务步骤相对少呢,编译工人其实也不会比解释工人高效出多少。甚至可能解释工人拿来就上手,编译工人还没读完,人家已经操作完了。又或者任务不需要重复执行(如实验代码),那么对着操作说明直接干就是了,没必要理解消化记忆。再者任务可能需要灵活性,每天需要根据厂长甚至是客户的要求改来改去,解释工人可能更加出色。每次改动,编译工人还要重新看一遍完整的操作说明(当然了,我们可以把操作说明分章节,那他只会看更新的章节),但是解释工人就不用这么麻烦,反正他都是读一条操作一步,你改不改动影响不大。

传统认知中的编译型、解释型、混合型

编译型

编译型:需通过编译器(compiler)将源代码编译成机器码,然后链接为可执行文件。这个过程对于在 Linux 下编译过代码的大家来说应该比较熟悉了,这里以 gcc 的工具链为例:

源代码(.c/.cpp) → 预处理(cpp) → 编译(cc1) → 汇编(as) → 链接(ld) → 可执行文件(.elf)

整个过程可参考:从C源代码到可执行文件的四个过程:预处理、编译、汇编、链接

  • 编译:把源代码编译成机器码;编译的过程又可分为:

    源代码 → 词法分析 → 语法分析→ 语义分析 → 中间代码生成 → 优化 → 目标代码生成 → 目标代码

    这就是大家熟悉的编译原理中学习过的的前中后端了。

  • 链接:把各个模块的机器码和依赖库串连起来生成可执行文件。链接也是有许多学问的,又可分为静态链接和动态链接。可参考:Linux下的ELF文件、链接、加载与库(含大量图文解析及例程)。

主流实现为编译型的语言有:C、C++、Object-C、swift 等。值得一提的是,Java 很多时候也被分类为编译型,这正是我们说所谓编译型语言的说法过时的原因,我们会在后面详细讨论 Java。

解释型

解释性语言的程序不需要编译,相比编译型语言省了道工序,解释性语言在运行程序的时候才逐行翻译。代表有 Python、JavaScript、PHP 等。

混合型

混合型:编译器将源码编译成中间码而不再是二进制机器码,然后中间码需要被即时编译器翻译成目标平台的本地代码。待表有:C#、Java。

编程语言及其实现

读者应该注意到上一小节我们的提法是编译型、解释型、混合型,而不是编译型语言、解释型语言、混合型语言

是这样的,即使有所谓的编译型、解释型之分,这种分类也是相对于语言的实现而言,而非语言本身。语言的本身只是规定了源代码的语法,至于怎样将源代码执行起来,这应当称为是语言的实现。那么对于语言的实现我们将其可以分为编译型、解释型和混合型

以下引自:计算机语言分类

将编程语言分类为编译型语言、解释型语言被认为是不科学的,因为很多语言既可以认为是解释型、也可以认为是编译型,这种分类方式被指出是不科学的,见于:RednaxelaFX 在 虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 中提到的:我是倾向于避开把编程语言描述为“编译型”或者“解释性”的。

详细地,下面以 Java 和 Python 为例子来解释这个问题。

Java 是这样从源码到被执行的(大致地~):

Java 源代码 -> javac 将其转为字节码(二进制码)->虚拟机中执行。

Java 按这种分类方式难以分类的原因就如上所示,首先编译其次在虚拟机中解释执行。为何说后者是解释?因为传统上我们认为从字节码到对应平台的机器码需要不同平台上的 JVM 提供支持,我们认为这个动作就是解释。

这样一来 Java 就难以按照这个分类方式进行分类了。实际上,我还是倾向于将 Java 称之为编译型语言,因为完全可以将 JVM 看做底层实现。这里粗粒度不宜过细,因为本质上说机器码被 CPU 接收然后运行,其中也涉及一段解释的过程。如此一来,世上只有解释型语言。

Python 虽然被普遍认为一门解释型语言,按理说应当不涉及编译过程。事实上,Python 解释器会将源代码转换为字节码(.pyc),然后再由 Python 解释器来执行这些字节码。本质上,Python 解释器不就是完成了编译器+执行器这个模块的任务,既然含有编译过程,那么其被称为解释型语言就具有一定不合理性。

R 大所认为的:语言一般只会定义其抽象语义,而不会强制性要求采用某种实现方式。而编译、解释只是实现方式的一个步骤或者方式,按这种分类是不合理的。

Python解释器与Java虚拟机

Python、Java对比的例子经常被用来说明这个问题。

Python 和 Java 的执行过程中都有字节码(.py和.class)的概念,它们的字节码都是既可以编译执行也可以解释执行的,这取决于后续处理这些字节码的 VM 的实现。

  • Python 的 VM 或者说 Runtime 有多种实现,CPython,JPython,PyPy,ironpython等,尤其是 PyPy 中是支持 JIT 即时编译的,还有 ironpython 的机制几乎就和 .NET 平台上的其他语言一样了。这使得 Python 也很难被直接归类为所谓的 ”解释型语言“ 了。但是 Python 中字节码(.pyc)不是必须的,而是可以直接由 Python解释器对源代码解释执行。可参考博客:python解释器。
  • Java 不同于 Python,它是一定要先编译一步拿到字节码 (.class) 的,这也是为什么 Java 常被分类为 “编译型语言”。但是在 JVM 拿到字节码之后,Java 的 JVM 的实现就很多样了,可以解释,可以编译,编译又可以分为 JIT 和 AOT。选择多多,细节多多。因此,Java 也可以被认为是混合型。可参考:Java一次编译,到处运行是如何实现的 和 JIT(动态编译)和AOT(静态编译)编译技术比较

以下参考自:凭啥Java的运行环境称虚拟机,Python的只能称解释器

看到Stackoverflow上有个问题在讨论Java和Python的对比,其中就有人问答为啥Java的运行环境被称之为JVM,而Python的只能叫做Interpreter。

这个问题估计想过的人不多,先找维基百科看一下虚拟机的定义。

虚拟机的定义有2个,一种是类似Vmware的系统虚拟机,另一种是虚拟机称之为程序虚拟机,诸如JVM,CLR就是最常见到的虚拟机。

程序虚拟机也称作托管运行时环境,运行这个虚拟机时,就好比普通的OS中的一个进程。当这个进程启动时,虚拟机启动,当进程销毁时,虚拟机销毁。使用虚拟机的目的就是提供一个和平台无关的编程环境。

JVM中的执行引擎只能处理编译后的Java字节码,字节码处理引擎其实包含一个字节码解释器和一个JIT编译器(和.net的CLR中JIT差别很大),解释器逐条的执行字节码指令,速度稍慢。JIT编译器则会将热点代码编译缓存起来,因此执行速度加快。

解释器的概念比较简单,它可以将代码翻译,并运行,不需要经过编译,JVM中的解释器正式这样的,JVM中解释的就是字节码。解释器运行程序的方法有3种:

  1. 直接运行高级编程语言(如Shell内置的解释器)
  2. 转换高级编程语言码到一些有效率的字节码(Bytecode),并运行这些字节码
  3. 以解释器包含的编译器对高级语言编译,并指示处理器运行编译后的程序(例如:JIT)

其中Python的解释器就是属于第二种,Python代码在首次运行时,它会将Python代码编译成字节码,如果可以的话,它会将这个字节码保存到**.pyc文件**中,这样下次启动的时候就不会再编译这些代码而是直接解释运行字节码。事实上,这种机制正在模糊解释器和编译器之间的界限,或者说是模糊了解释型语言和编译型语言的界限。

通过JVM和解释器的概念澄清,似乎还是不明白为啥JVM就被称为虚拟机,JVM中有运行的是字节码,它可能直接被解释执行,也可能被再次编译成目标语言,Python中的解释器也会先预编译Python代码为字节码,再解释执行。那么到底有啥区别?

很多人参与了讨论,分别从不同的角度去阐述区别。

有人认为虚拟机是和语言无关的,JVM为例,除了Java之外,Scala,Clojure,甚至Python借助于Jython工具,也可以运行在JVM上,而没听说什么语言能有Python解释器解释执行,除了Python。

也有人从语言的类型上,Java为静态类型的语言,而Python为动态语言。这使得Java字节码既可以被解释执行也可以被编译成机器指令再执行。而Python则复杂多了,它虽然让程序员可以不去关注变量的类型,但解释器不得不去推断数据类型,这一定程度上影响性能。

还有观点认为解释器是一个历史遗留术语,现代语言中虚拟机和解释器的分界已经很模糊甚至不存在。

事实上,在《Learning Python》一书中,作者把Python的解释器称为PVM。PVM是一个栈结构虚拟机(这里虚拟机分为基于栈的和基于寄存器的),它把字节码中的指令一条条执行过来就行。不用转换字节码。基于这个事实来讲,可以认为解释器和虚拟机的区别正在越来越小,已经是我中有你,你中有我的地步。独立的分割来看,可能还能区分这几步是解释器行为,这几步是虚拟机的行为,但是作为一个整体来看,两者的区别确实没那么明显。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532643.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常见的各种shell及其区别

常见的各种shell及其区别 引子 for((i1;i<10;i)); do echo $(expr $i \* 3 1); done 网上搜到的 shell for循环脚本&#xff0c;别人都能正常运行&#xff0c;我却报错&#xff1a; Syntax error: Bad for loop variable究竟是怎么回事呢&#xff1f; shell简介…

shell脚本 变量

shell脚本 变量类型 什么是Shell变量 用一个固定的字符串去表示不固定的内容。 Shell变量的类型 shell脚本中自定义变量的类型&#xff0c;我们这里分为&#xff1a; 自定义变量环境变量位置变量与定义变量 这四类&#xff0c;它们有一些相同点&#xff0c;但又有些不同点…

攻防世界web新手区解题 /cookie / disabled_button / weak_auth

cookie 题目描述&#xff1a;X老师告诉小宁他在cookie里放了些东西&#xff0c;小宁疑惑地想&#xff1a;‘这是夹心饼干的意思吗&#xff1f;’ 使用burp suite抓包查看 发现提示&#xff1a; look-herecookie.php 于是在url后加上 cookie.php 得到提示查看返回 就得到了f…

Python 函数式编程

Python 函数式编程 转自&#xff1a;https://www.liaoxuefeng.com/wiki/1016959663602400/1017328525009056&#xff0c;推荐去该链接读原文&#xff0c;有习题和热烈的评论区交流。 函数式编程 函数是Python内建支持的一种封装&#xff0c;我们通过把大段代码拆成函数&…

Python中的生成器与迭代器

Python中的生成器与迭代器 转自&#xff1a;https://www.liaoxuefeng.com/wiki/1016959663602400/1017323698112640&#xff0c;推荐去该链接读原文&#xff0c;有习题和热烈的评论区交流。 生成器 通过列表生成式&#xff0c;我们可以直接创建一个列表。但是&#xff0c;受…

基于GET报错的sql注入,sqli-lab 1~4

根据注入类型可将sql注入分为两类&#xff1a;数字型和字符型 例如&#xff1a; 数字型&#xff1a; sleect * from table where if 用户输入id 字符型&#xff1a;select * from table where id 用户输入id &#xff08;有引号) 通过URL中修改对应的D值&#xff0c;为正常数字…

Python 装饰器详解(上)

Python 装饰器详解&#xff08;上&#xff09; 转自&#xff1a;https://blog.csdn.net/qq_27825451/article/details/84396970&#xff0c;博主仅对其中 demo 实现中不适合python3 版本的语法进行修改&#xff0c;并微调了排版&#xff0c;本转载博客全部例程博主均已亲测可行…

xss原理和注入类型

XSS漏洞原理 : XSS又叫CSS(cross Site Script), 跨站脚本攻击,指的是恶意攻击者往Web页面里插入恶意JS代码,当用户浏览该页时,嵌入其中的Web里的JS代码就会被执行,从而达到恶意的特殊目的. 比如:拿到cooike XSS漏洞分类: 反射性(非存储型) payload没有经过存储,后端接收后,直接…

Python 装饰器详解(中)

Python 装饰器详解&#xff08;中&#xff09; 转自&#xff1a;https://blog.csdn.net/qq_27825451/article/details/84581272&#xff0c;博主仅对其中 demo 实现中不适合python3 版本的语法进行修改&#xff0c;并微调了排版&#xff0c;本转载博客全部例程博主均已亲测可行…

存储型xss案例

存储型xss原理: 攻击者在页面插入xss代码,服务端将数据存入数据库,当用户访问存在xss漏洞的页面时,服务端从数据库取出数据展示到页面上,导致xss代码执行,达到攻击效果 案例: 在一个搭建的论坛网站中, 根据存储型xss注入的条件,要找到可以存储到数据库的输入位置,并且这个位置…

反射型XSS案例

**原理:**攻击者将url中插入xss代码,服务端将url中的xss代码输出到页面上,攻击者将带有xss代码的url发送给用户,用户打开后受到xss攻击 需要url中有可以修改的参数 案例: 可能存在反射型xss的功能(点) : 搜索框等&#xff08;所有url会出现参数的地方都可以尝试&#xff09;……

Python 装饰器详解(下)

Python 装饰器详解&#xff08;下&#xff09; 转自&#xff1a;https://blog.csdn.net/qq_27825451/article/details/84627016&#xff0c;博主仅对其中 demo 实现中不适合python3 版本的语法进行修改&#xff0c;并微调了排版&#xff0c;本转载博客全部例程博主均已亲测可行…

xss-lab靶场通关writeup(1~6.......在更新)

level 2 : 标签被编码&#xff0c;利用属性完成弹窗 输入 发现没有弹窗 查看源代码&#xff1a; 发现&#xff1a; <>符号被编码 说明keybord参数进行了处理&#xff0c;那么只能从属性上进行恶意编码&#xff1a;先将属性的引号和标签闭合&#xff0c;用 // 将后面的…

PyTorch 分布式训练DDP 单机多卡快速上手

PyTorch 分布式训练DDP 单机多卡快速上手 本文旨在帮助新人快速上手最有效的 PyTorch 单机多卡训练&#xff0c;对于 PyTorch 分布式训练的理论介绍、多方案对比&#xff0c;本文不做详细介绍&#xff0c;有兴趣的读者可参考&#xff1a; [分布式训练] 单机多卡的正确打开方式…

Linux free 命令详解

Linux free 命令详解 free 命令用来查看系统中已用的和可用的内存。 命令选项及输出简介 关于各种命令的功能和命令选项&#xff0c;还是推荐英语比较好的同学直接看手册 RTFM&#xff1a;man free。这里简单总结一下一些重点&#xff1a; 功能及输出简介 free 命令显示系…

CTF web题 wp:

1.签到题 火狐F12查看源码&#xff0c;发现注释&#xff1a; 一次base64解码出flag 2.Encode 在这里插入图片描述 和第一题界面一样&#xff1f;&#xff1f; 轻车熟路f12&#xff1a; 发现编码&#xff1a; 格式看上去是base64&#xff0c;连续两次base64后&#xff0c;观…

【深度学习】深入理解Batch Normalization批归一化

【深度学习】深入理解Batch Normalization批归一化 转自&#xff1a;https://www.cnblogs.com/guoyaohua/p/8724433.html 这几天面试经常被问到BN层的原理&#xff0c;虽然回答上来了&#xff0c;但还是感觉答得不是很好&#xff0c;今天仔细研究了一下Batch Normalization的原…

ThinkPHP V5 漏洞利用

ThinkPHP 5漏洞简介 ThinkPHP官方2018年12月9日发布重要的安全更新&#xff0c;修复了一个严重的远程代码执行漏洞。该更新主要涉及一个安全更新&#xff0c;由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的情况下可能的getshell漏洞&#xff0c;受影响的版本…

Vim 重复操作的宏录制

Vim 重复操作的宏录制 转自&#xff1a;https://www.cnblogs.com/ini_always/archive/2011/09/21/2184446.html 在编辑某个文件的时候&#xff0c;可能会出现需要对某种特定的操作进行许多次的情况&#xff0c;以编辑下面的文件为例&#xff1a; ; ;This is a sample config…

Vim 进阶1

Vim 进阶1 所有你觉得简单重复&#xff0c;可以自动化实现的操作&#xff0c;都是可以自动化实现的。 Vim光标移动拾遗 w&#xff1a;下一个单词的开头&#xff0c;e&#xff1a;下一个单词的结尾&#xff0c;b&#xff1a;上一个单词的开头&#xff0c; 0&#xff1a;行首…