上一章我們已經(jīng)了解到,編程語言其實(shí)就是一種我們?nèi)祟愐子诶斫獾某绦蛘Z言。我們用這種編程語言編寫的程序就稱為源代碼。這些源代碼是通過翻譯器這么個(gè)東西,被翻譯成二進(jìn)制指令,從而讓計(jì)算機(jī)能夠執(zhí)行我們的指令。
那么,這其中發(fā)揮很大作用的翻譯器又是怎么回事?
編譯型語言與解釋型語言
其實(shí),翻譯器不止一種。我們根據(jù)翻譯器翻譯的時(shí)機(jī),將它分為了編譯器和解釋器。
相應(yīng)的,編程語言也分為了編譯型語言和解釋型語言。
編譯型語言要求將所有的源代碼通過編譯器轉(zhuǎn)換成二進(jìn)制指令,也就是生成一個(gè)可執(zhí)行程序(比如Windows下的.exe文件),比如匯編語言、C語言、C++等都是編譯型語言。
解釋型語言,顧名思義就是將源代碼一邊轉(zhuǎn)換,一邊執(zhí)行。就好像你閱讀文章一樣,讀到哪程序執(zhí)行到哪。這種方式不需要生成可執(zhí)行程序,使用會(huì)更加方便,比如Python、PHP、JavaScript、MATLAB等都是解釋型語言。
雖然文中對(duì)編譯器和解釋器講解的比較簡(jiǎn)單,但事實(shí)上,翻譯源代碼的過程十分復(fù)雜,過程大致包括詞法分析、語法分析、語義分析、性能優(yōu)化、生成可執(zhí)行文件等5個(gè)步驟,其中涉及到復(fù)雜的算法和硬件架構(gòu),這一點(diǎn)本文不再贅述。
操作系統(tǒng)
另外大家需要了解的一點(diǎn)是,計(jì)算機(jī)程序都是運(yùn)行在操作系統(tǒng)中的,目前我們比較熟知的操作系統(tǒng)平臺(tái)都有Windows、Linux、MacOS,當(dāng)然這三種操作系統(tǒng)都不是瞬間誕生的,也都經(jīng)歷了操作系統(tǒng)幾十年的發(fā)展,才完善成我們目前熟知的版本。
長(zhǎng)時(shí)間不同發(fā)展,導(dǎo)致不同的操作系統(tǒng)平臺(tái)之間底層的內(nèi)部結(jié)構(gòu)截然不同,也就是說能夠在Windows系統(tǒng)運(yùn)行的程序,拿到MacOS下便會(huì)無法運(yùn)行,同理,能在Linux平臺(tái)下執(zhí)行的程序,也不能在Windows平臺(tái)下執(zhí)行。
另外,就算是相同的操作系統(tǒng),不同的版本之間也不一定兼容。比如不能將Windows64位程序拿到Windows32位平臺(tái)下運(yùn)行。但反之一般都可以,這是因?yàn)?4位Windows對(duì)32位程序做了兼容性處理。這也是幾乎所有程序版本之間的通病,新版本可以兼容老版本,老版本兼容不了新版本。
除了程序不能跨平臺(tái)使用之外,源代碼也不能跨平臺(tái)使用。例如C語言中,可以讓程序暫停的“睡眠”函數(shù),在Windows平臺(tái)下函數(shù)名是Sleep,但在Linux平臺(tái)下該函數(shù)名是sleep,首字母大小寫不同。而且函數(shù)中的參數(shù)含義也不同,Sleep的參數(shù)是毫秒,sleep的參數(shù)是秒。
這是一件相當(dāng)麻煩的事情,這意味著同一個(gè)軟件,你不僅需要開發(fā)3種不同的源代碼,還要生成3種平臺(tái)的可執(zhí)行程序,分別兼容Windows、Linux、Mac OS這3種平臺(tái)(現(xiàn)在大部分軟件都有不同操作系統(tǒng)下的版本就是因?yàn)檫@個(gè)原因),未來的更新維護(hù)也需要同時(shí)更新3個(gè)版本。而且,萬一以后新出來個(gè)鴻蒙操作系統(tǒng),是不是又需要從頭開發(fā)新的版本呢?
當(dāng)然,以程序員的勤勞度來看,是不會(huì)做出這么費(fèi)力不討好的事情的。事實(shí)上,程序員有各種方法來解決這個(gè)問題。
比較經(jīng)典的辦法,就是開發(fā)一套支持跨平臺(tái)的語言。誕生于1995年的Java就是其中的引領(lǐng)者。目前國(guó)內(nèi)Java之所以火爆,很大部分原因就是Java的跨平臺(tái)特性。雖然后來微軟的C#也追隨了Java的腳步,但由于更新太慢,幾乎都要被人遺忘了。至于C語言,C++,由于太古老,它們誕生的時(shí)候還沒有操作系統(tǒng)呢,所以基本指望不上跨平臺(tái)了。
跨平臺(tái)語言運(yùn)行原理
編譯型語言
事實(shí)上,關(guān)于跨平臺(tái),編譯型語言和解釋型語言走上了不同的道路。雖然道路不同,但原理是一樣的。
比如Java這門語言,之所以能夠跨平臺(tái),是因?yàn)樗诓僮飨到y(tǒng)上層,又搭建了一個(gè)叫做Java虛擬機(jī)(Java Virtual Machine,簡(jiǎn)稱 JVM)的東西。你可以把JVM理解成一個(gè)底層軟件,而且針對(duì)不同的平臺(tái)有不同的版本:Windows版,Linux版、MacOS版,這三個(gè)版本的JVM安裝在了這三個(gè)平臺(tái)上,我們編寫的Java源代碼會(huì)被JVM轉(zhuǎn)換成字節(jié)碼,字節(jié)碼是可以在Java虛擬機(jī)上運(yùn)行的。流程如下圖:

這樣一來,你只需要寫一份源代碼就可以了,只要在操作系統(tǒng)中安裝上對(duì)應(yīng)的Java虛擬機(jī),就可以平滑運(yùn)行Java軟件了。所以Java打出的口號(hào)就是:一次編譯,處處運(yùn)行。

解釋型語言
相對(duì)于編譯型這種只有少數(shù)語言支持跨平臺(tái)的語言來說,解釋型語言幾乎都能跨平臺(tái)。“一次編寫,處處運(yùn)行”就是解釋型語言的特點(diǎn)。
那么為什么解釋型語言就能跨平臺(tái)呢?
這一切其實(shí)都?xì)w功于解釋器。
解釋器其實(shí)就類似于Java虛擬機(jī),也是編程語言與操作系統(tǒng)之間的中間層。官方會(huì)針對(duì)不同的平臺(tái)開發(fā)不同的解釋器,這些解釋器會(huì)把同樣的源代碼在不同的操作平臺(tái)下轉(zhuǎn)換成對(duì)應(yīng)平臺(tái)“認(rèn)識(shí)”的機(jī)器碼,兼容了不同平臺(tái)之間的差異,從而解決了跨平臺(tái)的問題。
編譯型和解釋型語言另外一個(gè)明顯的區(qū)別就是:
使用編譯型語言開發(fā)的可執(zhí)行程序,源代碼是無法獲取的,所以程序一般是閉源的。
而解釋型語言由于一邊轉(zhuǎn)換一邊執(zhí)行的特性,軟件下載下來的都是源代碼,否則就無法運(yùn)行,所以解釋型語言的程序一般是開源的。

關(guān)于Python
Python屬于解釋型語言,所以運(yùn)行Python程序需要安裝對(duì)應(yīng)平臺(tái)的解釋器。也就是說我們使用Python無需考慮不同平臺(tái)的兼容性問題,目前常見的如Linux、Windows、MacOS、Android、PocketPC等操作系統(tǒng),Python都可以完美運(yùn)行!
總結(jié)
我們將編譯型語言和解釋型語言的差異總結(jié)如下:
| 類型 | 原理 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|---|
| 編譯型語言 | 通過編譯器將源代碼轉(zhuǎn)換為操作系統(tǒng)平臺(tái)對(duì)應(yīng)的機(jī)器碼 | 編譯一次,脫離編譯器也能運(yùn)行,效率高 | 可移植性差,不夠靈活 |
| 解釋型語言 | 通過解釋器將源代碼轉(zhuǎn)換為操作系統(tǒng)平臺(tái)對(duì)應(yīng)的機(jī)器碼 | 跨平臺(tái)性好。 | 邊轉(zhuǎn)換機(jī)器碼邊執(zhí)行,效率較低 |