你知道「編譯」與「解釋」的區別嗎?

JerryC發表於2016-12-18

最近在看一些編譯過程的知識點,看的比較多的是英文文獻。
在這之間經常遇到的兩個單詞讓我著實迷惑:Compiler, Interpreter
中文翻譯分別是:編譯器,直譯器。

如果有人問我們「你知道什麼是編譯器麼?」,
我們很有可能首先蔑視一下這個人,然後說:「知道啊,不就編譯程式語言的程式嘛!」
要是別人再追問一句「那你知道直譯器麼?」,
這時候很有可能也會說「知道啊。」,但是很難再帶有蔑視的語氣了。
要是再問一句「那麼編譯器和直譯器的區別是什麼啊?」,
「呃......」

那麼到底什麼是「編譯器」,什麼是「直譯器」?
雖然對於兩個詞,我們很「耳熟」,但是「能詳」麼?
似乎我們並沒有認真對待這兩個詞彙。

什麼是編譯器

摘自 Wiki Compiler 一段

A compiler is a computer program (or a set of programs) that transforms source code written in a programming language (the source language) into another computer language (the target language), with the latter often having a binary form known as object code. The most common reason for converting source code is to create an executable program.

大概意思:

編譯器是一種計算機程式,負責把一種程式語言編寫的原始碼轉換成另外一種計算機程式碼,後者往往是以二進位制的形式被稱為目的碼(object code)。這個轉換的過程通常的目的是生成可執行的程式。

編譯器的產出是「另外一種程式碼」,然後這些程式碼等著被別人拿來執行,如果還不能直接被執行,那麼還需要再編譯或解釋一遍,再交由計算機硬體執行。
編譯器,往往是在「執行」之前完成,產出是一種可執行或需要再編譯或者解釋的「程式碼」。

什麼是直譯器

摘自 Wiki Interpreter 一段

In computer science, an interpreter is a computer program that directly executes, i.e. performs, instructions written in a programming or scripting language, without previously compiling them into a machine language program. An interpreter generally uses one of the following strategies for program execution:

  1. parse the source code and perform its behavior directly.
  2. translate source code into some efficient intermediate representation and immediately execute this.
  3. explicitly execute stored precompiled code made by a compiler which is part of the interpreter system.

大概意思:

在電腦科學中,直譯器是一種計算機程式,它直接執行由程式語言或指令碼語言編寫的程式碼,並不會把原始碼預編譯成機器碼。一個直譯器,通常會用以下的姿勢來執行程式程式碼:

  1. 分析原始碼,並且直接執行。
  2. 把原始碼翻譯成相對更加高效率的中間碼,然後立即執行它。
  3. 執行由直譯器內部的編譯器預編譯後儲存的程式碼

可以把直譯器看成一個黑盒子,我們輸入原始碼,它就會實時返回結果。
不同型別的直譯器,黑盒子裡面的構造不一樣,有些還會整合編譯器,快取編譯結果,用來提高執行效率(例如 Chrome V8 也是這麼做的)。
直譯器通常是工作在「執行時」,並且對於我們輸入的原始碼,是一行一行的解釋然後執行,然後返回結果。

分兩個維度比較一下

表現 Behavior

  • 編譯器把原始碼轉換成其他的更低階的程式碼(例如二進位制碼、機器碼),但是不會執行它。
  • 直譯器會讀取原始碼,並且直接生成指令讓計算機硬體執行,不會輸出另外一種程式碼。

效能 Performance

  • 編譯器會事先用比較多的時間把整個程式的原始碼編譯成另外一種程式碼,後者往往較前者更加接近機器碼,所以執行的效率會更加高。時間是消耗在預編譯的過程中。
  • 直譯器會一行一行的讀取原始碼,解釋,然後立即執行。這中間往往使用相對簡單的詞法分析、語法分析,壓縮解釋的時間,最後生成機器碼,交由硬體執行。直譯器適合比較低階的語言。但是相對於預編譯好的程式碼,效率往往會更低。如何減少解釋的次數和複雜性,是提高直譯器效率的難題。

關於程式碼,需要知道的幾個概念

在看了不少不多關於「編譯和解釋」的文章之後,我發現下面的詞彙是大量出現的。
知道這些詞彙代表的意思,以及對應的層次,能夠更好地看懂別人所要表達的意思。

高階語言程式碼 High-Level Code

高階語言程式碼,自然是指由高階程式語言編寫程式碼,對計算機的細節有更高層次的抽象。
相對於低階程式語言(low-level programming language)更接近自然語言(人類的語言)。
整合一系列的自動工具(垃圾回收,記憶體管理等),會讓程式設計師延長壽命,更快樂的編寫出更簡潔,更易讀的程式程式碼。

低階語言程式碼 Low-Level Code

低階語言程式碼,指由低階程式語言編寫的程式碼,相對高階語言,少了更多的抽象概念,更加接近於彙編或者機器指令。
但是這也意味著程式碼的可移植性很差。

在我看來,高與低,只是一組相對詞而已。
越高階的語言,效能、自由度越不及低階語言。
但是在抽象、可讀可寫性、可移植性越比低階語言優秀。
在以前的年代,C/C++語言相對組合語言,機器指令來說,肯定是高階語言。
而到了今天,我們更多人對C語言偏向認知為「低階語言」。
或許未來世界的開發者,看我們現在所熟悉的Java、PHP、Python、ECMAScript等等,都是「low」到爆的語言。

組合語言 Assembly Language

組合語言作為一門低階語言,對應於計算機或者其他可程式設計的硬體。
它和計算機的體系結構以及機器指令是強關聯的。
換句話說,就是不同的組合語言程式碼對應特定的硬體,所以不用談可移植性了。
相對於需要編譯和解釋的高階語言程式碼來說,彙編程式碼只需要翻譯成機器碼就可以執行了。
所以組合語言也往往被稱作象徵性機器碼(symbolic machine code)

位元組碼 Byte Code

位元組碼嚴格來說不算是程式語言,而是高階程式語言為了種種需求(可移植性、可傳輸性、預編譯等)而產生的中間碼(Intermediate Code)。
它是由一堆指令集組成的程式碼,例如在javac編譯過後的java原始碼產生的就是位元組碼。
原始碼在編譯的過程中,是需要進行「詞法分析 → 語法分析 → 生成目的碼」等過程的,在預編譯的過程中,就完成這部分工作,生成位元組碼。
然後在後面交由直譯器(這裡通常指程式語言的虛擬機器)解釋執行,省去前面預編譯的開銷。

機器碼 Machine Code

機器碼是一組可以直接被CPU執行的指令集,
每一條指令都代表一個特定的任務,或者是載入,或者是跳轉,亦或是計算操作等等。
所有可以直接被CPU執行的程式,都是由這麼一系列的指令組成的。
機器碼可是看作是編譯過程中,最低階的程式碼,因外再往下就是交由硬體來執行了。
當然機器碼也是可以被編輯的,但是以人類難以看懂的姿勢存在,可讀性非常差。

從熟悉的程式語言的角度來看看

你知道「編譯」與「解釋」的區別嗎?
從熟悉的程式語言的角度來看

從左往右看,

  1. 以 Java 為例,我們在文字編譯器寫好了 Java 程式碼,交由「編譯器」編譯成 Java Bytecode。然後 Bytecode 交由 JVM 來執行,這時候 JVM 充當了「直譯器」的角色,在解釋 Bytecode 成 Machine Code 的同時執行它,返回結果。
  2. BASIC 語言(早期的可以由計算機直譯的語言) 為例,通過文字編譯器編寫好,不用經歷「編譯」的過程,就可以直接交由作業系統內部來進行「解釋」然後執行。
  3. 以 C 語言為例,我們在文字編譯器編寫好原始碼,然後執行 gcc hello.c 編譯出 hello.out 檔案,該檔案由一系列的機器指令組成的機器碼,可以直接交由硬體來執行。

抽象看本質:人與計算機之間的鴻溝

無論是最近在看《暗時間》的作者劉未鵬,還是前一段時間聽《以產品思維寫文章》講座的阿禪,還是其他的很多聰明的人。
他們都強調「抽象看本質」的能力,能從事物本身抽象出共通屬性,看待本質。
這也是很多人所說的「跳出這個框框再看」的思維方式。

無論是「編譯 Compile」還是「解釋 Interpret」。
本質還是「人與計算機的交流形式」,人的語言最終轉換成機器語言。
一句 「Hello World」,經過一些列的「編譯」和「解釋」,最終轉換成一系列包含機器指令的那些0和1,機器傻傻執行完之後,告訴你結果。

就這麼一個過程,我們就需要很多的翻譯官。
有些翻譯官可以做到同聲傳譯(解釋),有些翻譯官卻只能把我們的意圖記下來再全部翻譯(編譯)給計算機。
而往往一個翻譯官能力有限,也只能把你的語言,翻譯成另外一種低階點的語言,再由另外懂這個語言的翻譯官來翻譯更接近計算機能讀得懂的語言。

你知道「編譯」與「解釋」的區別嗎?
人類和計算機的鴻溝.png

一句話描述「編譯」與「解釋」?

不如這張圖來得直接:

你知道「編譯」與「解釋」的區別嗎?
一句話描述編譯與解釋

編譯 Compile:把整個程式原始碼翻譯成另外一種程式碼,然後等待被執行,發生在執行之前,產物是「另一份程式碼」。
解釋 Interpret:把程式原始碼一行一行的讀懂然後執行,發生在執行時,產物是「執行結果」。

參考

stackoverflow.com/questions/2…
www.wikiwand.com/en/Interpre…)
www.wikiwand.com/en/Compiler
www.wikiwand.com/en/Machine_…
www.wikiwand.com/en/High-lev…
www.wikiwand.com/en/Low-leve…
www.wikiwand.com/en/Bytecode

關於轉載

本文預設允許轉載,但:

  1. 請務必註明出處:BlueSun | 《你知道「編譯」與「解釋」的區別嗎?」》
  2. 如果你不介意,我希望轉載的同時,可以得到一聲告知。(Email:huangjerryc@gmail.com)

感謝!

相關文章