編譯型語言與解釋型語言

編譯型語言與解釋型語言

首先要說明,編譯型語言與解釋型語言這種分類方法是不科學的,或者說已經過時了,但是這種稱呼大抵還是能夠讓人明白我們將要討論的是什么東西。

文中所列參考是筆者認為比較有幫助的一些擴展閱讀內容。

首先貼一個很形象的比喻,來自知乎@孛爾只斤南丁:

假設廠里來了兩個新工人,一個叫編譯,另一個叫解釋。廠長(程序員)給他們安排了一項任務(需求),并發放了操作說明(源代碼)。

編譯這名工人的做法是先完整的看一遍操作說明,遇到錯別字或者不明白的地方,就去問廠長,直到操作說明最終成為一個沒有錯別字且他自己完全能夠理解的東西。然后他把操作說明的內容理解消化(編譯),并且變成記憶(可執行程序)。之后每次需要完成任務的時候就靠自己的理解和記憶去執行,不再需要操作說明。

我們再看解釋這個工人。他拿到操作說明二話不說直接上手,讀一條,操作一步,再讀一條,操作下一步,如此重復。就算是操作說明中有錯別字或者他看不懂的地方,在沒有讀到那一條之前他是不知道的,也不影響他進行前面的操作,等真的讀到錯別字或者不能理解的條目再去問廠長。而且不管他執行這個任務執行了多少次,每次都是需要看著操作說明一步一步執行。

那這兩個工人誰好誰壞呢?難說。

如果給他們安排的任務以后要重復很多次,而且步驟繁多,但是相對穩定不需要頻繁調整,那么編譯工人的工作效率可能會更高一些。因為任務相對穩定不需要調整,所以他只要第一次把不明白的地方跟廠長問清楚,自己理解消化記住了,以后的執行都是他自己內化理解的東西,做起來很快。

如果任務步驟相對少呢,編譯工人其實也不會比解釋工人高效出多少。甚至可能解釋工人拿來就上手,編譯工人還沒讀完,人家已經操作完了。又或者任務不需要重復執行(如實驗代碼),那么對著操作說明直接干就是了,沒必要理解消化記憶。再者任務可能需要靈活性,每天需要根據廠長甚至是客戶的要求改來改去,解釋工人可能更加出色。每次改動,編譯工人還要重新看一遍完整的操作說明(當然了,我們可以把操作說明分章節,那他只會看更新的章節),但是解釋工人就不用這么麻煩,反正他都是讀一條操作一步,你改不改動影響不大。

傳統認知中的編譯型、解釋型、混合型

編譯型

編譯型:需通過編譯器(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.pswp.cn/news/532643.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532643.shtml
英文地址,請注明出處:http://en.pswp.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;行首…