歡迎來(lái)我的博客閱讀:《你知道「編譯」和「解釋」的區(qū)別嗎哪替?》
最近在看一些編譯過(guò)程的知識(shí)點(diǎn),看的比較多的是英文文獻(xiàn)菇怀。
在這之間經(jīng)常遇到的兩個(gè)單詞讓我著實(shí)迷惑:Compiler, Interpreter
中文翻譯分別是:編譯器凭舶,解釋器晌块。
如果有人問(wèn)我們「你知道什么是編譯器么?」帅霜,
我們很有可能首先蔑視一下這個(gè)人匆背,然后說(shuō):「知道啊,不就編譯編程語(yǔ)言的程序嘛身冀!」
要是別人再追問(wèn)一句「那你知道解釋器么钝尸?」,
這時(shí)候很有可能也會(huì)說(shuō)「知道啊搂根≌浯伲」,但是很難再帶有蔑視的語(yǔ)氣了剩愧。
要是再問(wèn)一句「那么編譯器和解釋器的區(qū)別是什么爸硇稹?」仁卷,
「呃......」
那么到底什么是「編譯器」穴翩,什么是「解釋器」?
雖然對(duì)于兩個(gè)詞五督,我們很「耳熟」,但是「能詳」么瓶殃?
似乎我們并沒(méi)有認(rèn)真對(duì)待這兩個(gè)詞匯充包。
什么是編譯器
摘自 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.
大概意思:
編譯器是一種計(jì)算機(jī)程序,負(fù)責(zé)把一種編程語(yǔ)言編寫(xiě)的源碼轉(zhuǎn)換成另外一種計(jì)算機(jī)代碼遥椿,后者往往是以二進(jìn)制的形式被稱為目標(biāo)代碼(object code)基矮。這個(gè)轉(zhuǎn)換的過(guò)程通常的目的是生成可執(zhí)行的程序。
編譯器的產(chǎn)出是「另外一種代碼」冠场,然后這些代碼等著被別人拿來(lái)執(zhí)行家浇,如果還不能直接被執(zhí)行,那么還需要再編譯或解釋一遍碴裙,再交由計(jì)算機(jī)硬件執(zhí)行钢悲。
編譯器,往往是在「執(zhí)行」之前完成舔株,產(chǎn)出是一種可執(zhí)行或需要再編譯或者解釋的「代碼」莺琳。
什么是解釋器
摘自 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:
- parse the source code and perform its behavior directly.
- translate source code into some efficient intermediate representation and immediately execute this.
- explicitly execute stored precompiled code made by a compiler which is part of the interpreter system.
大概意思:
在計(jì)算機(jī)科學(xué)中,解釋器是一種計(jì)算機(jī)程序载慈,它直接執(zhí)行由編程語(yǔ)言或腳本語(yǔ)言編寫(xiě)的代碼惭等,并不會(huì)把源代碼預(yù)編譯成機(jī)器碼。一個(gè)解釋器办铡,通常會(huì)用以下的姿勢(shì)來(lái)執(zhí)行程序代碼:
- 分析源代碼辞做,并且直接執(zhí)行琳要。
- 把源代碼翻譯成相對(duì)更加高效率的中間碼,然后立即執(zhí)行它秤茅。
- 執(zhí)行由解釋器內(nèi)部的編譯器預(yù)編譯后保存的代碼
可以把解釋器看成一個(gè)黑盒子稚补,我們輸入源碼,它就會(huì)實(shí)時(shí)返回結(jié)果嫂伞。
不同類(lèi)型的解釋器孔厉,黑盒子里面的構(gòu)造不一樣,有些還會(huì)集成編譯器帖努,緩存編譯結(jié)果撰豺,用來(lái)提高執(zhí)行效率(例如 Chrome V8 也是這么做的)。
解釋器通常是工作在「運(yùn)行時(shí)」拼余,并且對(duì)于我們輸入的源碼污桦,是一行一行的解釋然后執(zhí)行,然后返回結(jié)果匙监。
分兩個(gè)維度比較一下
表現(xiàn) Behavior
- 編譯器把源代碼轉(zhuǎn)換成其他的更低級(jí)的代碼(例如二進(jìn)制碼凡橱、機(jī)器碼),但是不會(huì)執(zhí)行它亭姥。
- 解釋器會(huì)讀取源代碼稼钩,并且直接生成指令讓計(jì)算機(jī)硬件執(zhí)行,不會(huì)輸出另外一種代碼达罗。
性能 Performance
- 編譯器會(huì)事先用比較多的時(shí)間把整個(gè)程序的源代碼編譯成另外一種代碼坝撑,后者往往較前者更加接近機(jī)器碼,所以執(zhí)行的效率會(huì)更加高粮揉。時(shí)間是消耗在預(yù)編譯的過(guò)程中巡李。
- 解釋器會(huì)一行一行的讀取源代碼,解釋扶认,然后立即執(zhí)行侨拦。這中間往往使用相對(duì)簡(jiǎn)單的詞法分析、語(yǔ)法分析辐宾,壓縮解釋的時(shí)間狱从,最后生成機(jī)器碼,交由硬件執(zhí)行叠纹。解釋器適合比較低級(jí)的語(yǔ)言矫夯。但是相對(duì)于預(yù)編譯好的代碼,效率往往會(huì)更低吊洼。如何減少解釋的次數(shù)和復(fù)雜性训貌,是提高解釋器效率的難題。
關(guān)于代碼,需要知道的幾個(gè)概念
在看了不少不多關(guān)于「編譯和解釋」的文章之后递沪,我發(fā)現(xiàn)下面的詞匯是大量出現(xiàn)的豺鼻。
知道這些詞匯代表的意思,以及對(duì)應(yīng)的層次款慨,能夠更好地看懂別人所要表達(dá)的意思儒飒。
高級(jí)語(yǔ)言代碼 High-Level Code
高級(jí)語(yǔ)言代碼,自然是指由高級(jí)編程語(yǔ)言編寫(xiě)代碼檩奠,對(duì)計(jì)算機(jī)的細(xì)節(jié)有更高層次的抽象桩了。
相對(duì)于低級(jí)編程語(yǔ)言(low-level programming language)更接近自然語(yǔ)言(人類(lèi)的語(yǔ)言)。
集成一系列的自動(dòng)工具(垃圾回收埠戳,內(nèi)存管理等)井誉,會(huì)讓程序員延長(zhǎng)壽命,更快樂(lè)的編寫(xiě)出更簡(jiǎn)潔整胃,更易讀的程序代碼颗圣。
低級(jí)語(yǔ)言代碼 Low-Level Code
低級(jí)語(yǔ)言代碼,指由低級(jí)編程語(yǔ)言編寫(xiě)的代碼屁使,相對(duì)高級(jí)語(yǔ)言在岂,少了更多的抽象概念,更加接近于匯編或者機(jī)器指令蛮寂。
但是這也意味著代碼的可移植性很差蔽午。
在我看來(lái),高與低酬蹋,只是一組相對(duì)詞而已及老。
越高級(jí)的語(yǔ)言,性能除嘹、自由度越不及低級(jí)語(yǔ)言写半。
但是在抽象岸蜗、可讀可寫(xiě)性尉咕、可移植性越比低級(jí)語(yǔ)言優(yōu)秀。
在以前的年代璃岳,C/C++語(yǔ)言相對(duì)匯編語(yǔ)言年缎,機(jī)器指令來(lái)說(shuō),肯定是高級(jí)語(yǔ)言铃慷。
而到了今天单芜,我們更多人對(duì)C語(yǔ)言偏向認(rèn)知為「低級(jí)語(yǔ)言」。
或許未來(lái)世界的開(kāi)發(fā)者犁柜,看我們現(xiàn)在所熟悉的Java洲鸠、PHP、Python、ECMAScript等等扒腕,都是「low」到爆的語(yǔ)言绢淀。
匯編語(yǔ)言 Assembly Language
匯編語(yǔ)言作為一門(mén)低級(jí)語(yǔ)言,對(duì)應(yīng)于計(jì)算機(jī)或者其他可編程的硬件瘾腰。
它和計(jì)算機(jī)的體系結(jié)構(gòu)以及機(jī)器指令是強(qiáng)關(guān)聯(lián)的皆的。
換句話說(shuō),就是不同的匯編語(yǔ)言代碼對(duì)應(yīng)特定的硬件蹋盆,所以不用談可移植性了费薄。
相對(duì)于需要編譯和解釋的高級(jí)語(yǔ)言代碼來(lái)說(shuō),匯編代碼只需要翻譯成機(jī)器碼就可以執(zhí)行了栖雾。
所以匯編語(yǔ)言也往往被稱作象征性機(jī)器碼(symbolic machine code)
字節(jié)碼 Byte Code
字節(jié)碼嚴(yán)格來(lái)說(shuō)不算是編程語(yǔ)言楞抡,而是高級(jí)編程語(yǔ)言為了種種需求(可移植性、可傳輸性岩灭、預(yù)編譯等)而產(chǎn)生的中間碼(Intermediate Code)拌倍。
它是由一堆指令集組成的代碼,例如在javac
編譯過(guò)后的java源碼產(chǎn)生的就是字節(jié)碼噪径。
源碼在編譯的過(guò)程中柱恤,是需要進(jìn)行「詞法分析 → 語(yǔ)法分析 → 生成目標(biāo)代碼」等過(guò)程的,在預(yù)編譯的過(guò)程中找爱,就完成這部分工作梗顺,生成字節(jié)碼。
然后在后面交由解釋器(這里通常指編程語(yǔ)言的虛擬機(jī))解釋執(zhí)行车摄,省去前面預(yù)編譯的開(kāi)銷(xiāo)寺谤。
機(jī)器碼 Machine Code
機(jī)器碼是一組可以直接被CPU執(zhí)行的指令集,
每一條指令都代表一個(gè)特定的任務(wù)吮播,或者是加載变屁,或者是跳轉(zhuǎn),亦或是計(jì)算操作等等意狠。
所有可以直接被CPU執(zhí)行的程序粟关,都是由這么一系列的指令組成的。
機(jī)器碼可是看作是編譯過(guò)程中环戈,最低級(jí)的代碼闷板,因外再往下就是交由硬件來(lái)執(zhí)行了。
當(dāng)然機(jī)器碼也是可以被編輯的院塞,但是以人類(lèi)難以看懂的姿勢(shì)存在遮晚,可讀性非常差。
從熟悉的編程語(yǔ)言的角度來(lái)看看
從左往右看拦止,
- 以 Java 為例县遣,我們?cè)谖谋揪幾g器寫(xiě)好了 Java 代碼,交由「編譯器」編譯成 Java Bytecode。然后 Bytecode 交由 JVM 來(lái)執(zhí)行萧求,這時(shí)候 JVM 充當(dāng)了「解釋器」的角色括蝠,在解釋 Bytecode 成 Machine Code 的同時(shí)執(zhí)行它,返回結(jié)果饭聚。
- 以 BASIC 語(yǔ)言(早期的可以由計(jì)算機(jī)直譯的語(yǔ)言) 為例忌警,通過(guò)文本編譯器編寫(xiě)好,不用經(jīng)歷「編譯」的過(guò)程秒梳,就可以直接交由操作系統(tǒng)內(nèi)部來(lái)進(jìn)行「解釋」然后執(zhí)行法绵。
- 以 C 語(yǔ)言為例,我們?cè)谖谋揪幾g器編寫(xiě)好源代碼酪碘,然后運(yùn)行
gcc hello.c
編譯出hello.out
文件朋譬,該文件由一系列的機(jī)器指令組成的機(jī)器碼,可以直接交由硬件來(lái)執(zhí)行兴垦。
抽象看本質(zhì):人與計(jì)算機(jī)之間的鴻溝
無(wú)論是最近在看《暗時(shí)間》的作者劉未鵬徙赢,還是前一段時(shí)間聽(tīng)《以產(chǎn)品思維寫(xiě)文章》講座的阿禪,還是其他的很多聰明的人探越。
他們都強(qiáng)調(diào)「抽象看本質(zhì)」的能力狡赐,能從事物本身抽象出共通屬性,看待本質(zhì)钦幔。
這也是很多人所說(shuō)的「跳出這個(gè)框框再看」的思維方式枕屉。
無(wú)論是「編譯 Compile」還是「解釋 Interpret」。
本質(zhì)還是「人與計(jì)算機(jī)的交流形式」鲤氢,人的語(yǔ)言最終轉(zhuǎn)換成機(jī)器語(yǔ)言搀擂。
一句 「Hello World」,經(jīng)過(guò)一些列的「編譯」和「解釋」卷玉,最終轉(zhuǎn)換成一系列包含機(jī)器指令的那些0和1哨颂,機(jī)器傻傻執(zhí)行完之后,告訴你結(jié)果相种。
就這么一個(gè)過(guò)程威恼,我們就需要很多的翻譯官。
有些翻譯官可以做到同聲傳譯(解釋)蚂子,有些翻譯官卻只能把我們的意圖記下來(lái)再全部翻譯(編譯)給計(jì)算機(jī)沃测。
而往往一個(gè)翻譯官能力有限缭黔,也只能把你的語(yǔ)言食茎,翻譯成另外一種低級(jí)點(diǎn)的語(yǔ)言,再由另外懂這個(gè)語(yǔ)言的翻譯官來(lái)翻譯更接近計(jì)算機(jī)能讀得懂的語(yǔ)言馏谨。
一句話描述「編譯」與「解釋」别渔?
不如這張圖來(lái)得直接:
編譯 Compile:把整個(gè)程序源代碼翻譯成另外一種代碼,然后等待被執(zhí)行,發(fā)生在運(yùn)行之前哎媚,產(chǎn)物是「另一份代碼」喇伯。
解釋 Interpret:把程序源代碼一行一行的讀懂然后執(zhí)行,發(fā)生在運(yùn)行時(shí)拨与,產(chǎn)物是「運(yùn)行結(jié)果」稻据。
參考
http://stackoverflow.com/questions/2377273/how-does-an-interpreter-compiler-work
https://www.wikiwand.com/en/Interpreter_(computing)
https://www.wikiwand.com/en/Compiler
https://www.wikiwand.com/en/Machine_code
https://www.wikiwand.com/en/High-level_programming_language
https://www.wikiwand.com/en/Low-level_programming_language
https://www.wikiwand.com/en/Bytecode