為什麼程序語言會存在解釋型或編譯型的限制?

There is no such thing as an "interpreted language". A language is a set
of abstract mathematical rules. A language isn"t interpreted or
compiled, it just is. Interpretation and compilation are traits of, well, the interpreter or compiler (duh!), not the language.
Why are most functional programming languages also interpreted languages?
根據上述說法編程語言其實不存在所謂編譯型或解釋型的分類,只是編譯器/解釋器的限制。那麼問題來了:
1. 為什麼現實中會存在這樣的限制?
2. 為什麼C不提供交互執行的解釋器,Python沒有一個像C一樣直接編譯得到機器代碼的編譯器?
3. 做到像Haskell一樣卻既可以編譯又可以交互執行很困難嗎?還是說這樣做意義不大?
p.s.我知道還有其他語言也是能即解釋又編譯的,上面鏈接中就有例子,但畢竟不是主流,或者說大部分語言都是默認(官方)的偏向某一種。交互執行便於學習,編譯能夠提升性能,為什麼同時宣稱兩者的語言並不多?

相關問題:
程序的編譯與解釋有什麼區別? - 編程語言
這個問題其實包含了我的問題,但太寬泛了,得到的答案並沒有解決我的問題
programming languages


1、你買了一台電腦之後,你已經擁有了一個硬體解釋器(CPU),所以圍繞著到底是硬體來解釋還是軟體來解釋,就產生出了一大堆其實你不知道也可以的概念,譬如說古老的,在現在已經不再成立的編譯型和解釋型。

2、TCC(雖然並不交互但是他是解釋的所以只要你隨手一改)和pypy都哭了

3、C# interactive / F# interactive哭了

p.s. C#又哭了一次

p.s.s.為了讓題主開一下眼界,我決定告訴你,.net上的iron python在執行一個程序的整個過程里,有時候解釋,有時候編譯(逃


這句話是錯的。

編程語言從來沒有編譯型和解釋型之分,只能說一門編程語言的常見執行方式為編譯器編譯成新代碼(交給解釋器或者機器碼執行),或者解釋器解釋執行。

/*
已填坑
*/

0x00.首先,什麼是編譯器?

編譯器,簡單的說,就是一個程序,它的輸入是一種A語言的源代碼,輸出是一種B語言的源代碼。
當然,一般來說,A語言和B語言是不同的(但也有相同的情況,一般用於代碼優化或者代碼混淆……),比如C++編譯器,將C++源代碼編譯成為彙編代碼。

C++:

int foo(int a,int b,int c){
return a + b * c;
}
//Do som
foo(1,2,3);

彙編:

mov eax, dword ptr [esp + 8]
imul eax, dword ptr [esp + 0c]
add eax, dword ptr [esp + 4]
ret
;...
push 3
push 2
push 1
call foo
add esp, 0c

當然,有些人會說:「為什麼VS點"編譯"就直接生成一個可執行文件(.exe)了?難道(.exe)是彙編的文本流?」 這當然是否定的,因為其實那個叫做"build"而非單純的編譯,包括了鏈接(link)的步驟,在鏈接的時候(這裡拿靜態鏈接舉例)把你經過編譯得來的彙編代碼,中間的地址重定向為操作系統分配的地址,還有外部C++標準庫之類的,把對應的指令的地址重定向到相應的地址等等,讓這個純粹的類似宏彙編代碼能夠真正變成可被操作系統裝入內存的機器碼。

編譯過程中,並沒有要求編譯器表現出任何關於源代碼定義的行為,它是生成了一個能表現輸入源代碼行為的新的代碼。

0x01.那麼,解釋器呢?

解析器,其實就是一個程序,它的輸入是一種語言的源代碼,但是它直接執行了源代碼(意思是這個程序對外表現了這個源代碼定義的行為),比如Python的解析器,只要給定一個輸入,foo.py,那麼運行這個程序(帶上這個輸入),它的執行行為就表現為那個foo.py的行為。

foo.py的內容:

print "hello world!"

python解釋器執行:

xx:Python xx$ python foo.py
hello world!

其實,解釋器就是一個大黑箱,你就算不知道裡面究竟是什麼,但是你知道你的輸入的源代碼會被完整的執行出來。常見的,解釋器內部的實現也就是一個編譯器外加一個虛擬機,編譯器用來講輸入的源代碼生成中間代碼,而虛擬機將中間代碼一條條執行(這個執行一般指的是使用C寫的執行引擎程序來執行)

0x02.虛擬機
雖然這個玩意我不太懂(別打我……),但是一個虛擬機一般是由定義了的中間代碼語法,以及一個執行引擎組成,比如JVM和Java位元組碼,Zend Engine和Opcode。之所以不採用真實的物理機,一是因為物理機的指令集多,各種新架構新增的指令直接寫太困難,可移植苦難。俗話說的好

計算機領域只要多分幾層,沒有解決不了的問題

比如對於一門動態語言,直接做一個編譯器講這門語言和彙編鏈接到一起,難度太大(尤其是詞法分析上),這個時候可以採取間接的定義一套中間碼,講源代碼編譯成為中間碼,中間碼通過另一個程序(執行引擎,一般是C/C++寫的)執行這個中間碼,這樣效率不會損失太多但大大加快了開發效率。

Java:

int a = 0;
int b = 1;
int c = 2;
a = a + b * c;

Java位元組碼:

0: iconst_0
1: istore_1
2: iconst_1
3: istore_2
4: iconst_2
5: istore_3
6: iload_1
7: iload_2
8: iload_3
9: imul
10: iadd
11: istore_1
12: return

其實虛擬機執行引擎怎麼執行傳來的中間碼,這也是一個編譯/解釋的區別,前者就是直接將中間碼再次編譯為更底層(彙編級別,機器碼),並且保存到外存中,比如.NET的CLR;後者就是直接把這個中間碼按照一條條的指令直接執行(執行也就是用C的等價代碼來實現它),不會將新的代碼保存在外存中。這也是一個最大的區別吧。

0x03.總結一下
現如今,其實語言本身沒有任何要求你是採取編譯的方式生成二進位文件手動執行,還是解析的方式直接執行,但是一門語言的設計很可能會影響這個過程,因為你想要一個想讓Ruby做一個純粹的編譯器編譯成彙編,這個難度不是也太大了嘛……還不如直接把Ruby解釋器封裝一下(Ruby解釋器是用C寫的)

扯淡階段:其實所謂編譯型和解釋型遞歸到最後,都是編譯型,因為你無論如何都是把代碼轉換為二進位數嘛,而最後的執行,其實就是一個二進位數的第幾位所對應ALU的第幾號地址引腳的電平高低的變化而已,所以就沒有"解釋"這個過程,所以所有的東西都是編譯型(逃……)


1. 為什麼現實中會存在這樣的限制?

編譯=第一次執行前花費大量時間預處理,之後執行速度大幅上升
解釋=每一次執行速度一樣,但(普遍)比編譯後的速度慢

兩者基本上是同一條坐標軸的兩極,所以你只能選擇在兩者之間的位置,但不可能同時擁有兩極的特點

2. 為什麼C不提供交互執行的解釋器,Python沒有一個像C一樣直接編譯得到機器代碼的編譯器?
Python如果你願意的話完全可以自己寫一個到機器代碼的編譯器,但問題是一般用不著

Python完全可以有編譯器,只是沒有人用得到罷了。性能極端重要的場合幾乎所有人都會用C++或者C,其他場合Python的速度和主流語言差不多,沒必要特意編譯

至於C,你調試程序時候單步執行靠的就是解釋器

3. 做到像Haskell一樣卻既可以編譯又可以交互執行很困難嗎?還是說這樣做意義不大?
Linux那邊不知道,微軟這邊有個東西叫.Net Native,基本就是你說的意思。


http://blog.csdn.net/xtlisk/article/details/39091705


只要是主流語言都會有兩種類型的編譯器後端,例如c,c++,java,python,c#,都有,還有介於兩者之間的jit。如果其中一張編譯方式比較主流,那麼這不是限制,而是選擇。


理論上不會有區別,但工程上會有。編譯型語言的優勢在於編譯在一次完成,執行時代價小。那麼它就幾乎必然做成效率優先的語言,比如儘可能地優化、盡量讓語言特性對應機器特性,等等。解釋型語言通常會反過來。
最直接的,編譯時資源消耗的取捨。用C、C++編譯一個大項目,可能消耗幾分鐘的時間,在比較壞的情況下可能消耗小時級別的時間。由於解釋型語言每次都要「編譯」,這個時間就肯定是完全不可接受的。
解釋型語言通常不得到直接的native code,而是得到驅動runtime的專用指令。這樣,它就不能直接和native code的庫進行交互,非得弄個中間層才行。
然後,如果你的語言特性貼近機器,那麼就會受機器的限制。像Perl,函數是運行時hash查找的,參數和返回值是在一個自己的「堆棧」對象上的,因而可以玩各種花樣。而C什麼的就會比較死。


資源問題。普通的一門語言,哪有人給做不同的實現啊,作者自己做一個就完了。這個實現是編譯的,它就是編譯的;這個實現是解釋的,它就是解釋的。
只有各種熱門語言,才有很多人願意為不同的應用場景,給出多個實現。這樣的語言里,就沒有編譯和解釋的區別了。


需求決定一切


我司的通訊模塊自動化測試腳本就是用C寫的,解釋執行。


沒有這樣的限制。C可以交互執行,py可以編譯成原生代碼。不困難,意義不大


推薦閱讀:

零基礎如何迅速學習前端?
怎麼反駁大學老師說做軟體很簡單的觀點?
關於電腦操作,有什麼高效的方法工具?
程序員一定要熬夜嗎?有沒有可能白天就基本完成工作,每天早睡早起?
在使用了多年 C# 的情況下,如何轉型到 Objective-C 語言?

TAG:編程語言 | 編程 | 解釋器 | 編譯器 |