[程序設計語言]-01:引言


1.機器語言>匯編語言>高級語言

語言是人與人的一種交流工具,就比如我現在用漢語來寫這篇博文來交流探討技術問題;程序設計語言也是如此,只是交流對象不是人而是機器。我可以用漢語來寫博文,也可以用英語來寫(假如我英語熟練);我可以用PHP來寫一個網站,也可以用ASP.NET來寫。這就說明語言的本質就是一種交流工具,而我選擇哪種語言來交流並不會影響我要的結果。然而在實際中到底要選用那個語言確要根據具體情況而定,這是個成本問題,比如我如果今天腦子抽筋要用日語,那我寫着也累(關鍵是也不會)、讀者或許也會罵娘了。

早期的計算機是一台超級龐然大物,能耗抵得上一家小型工廠,而計算能力確不如今天的一台手持計算器。也就是當時人力成本要遠遠低於這台機器的機器成本,也就決定了當時是以機器為中心,而不是人。所以人們用計算機能直接理解的機器語言來編寫程序。這里有一個計算兩個整數的最大公約數的栗子(MIPS R4000處理器的機器語言),16進制形式如下:

1 2dbdffd0 afbf0014 oc1002a8 00000000 0c1002a8 afa2001c 8fa4001c
2 00401825 10820008 0064082a 10200003 00000000 10000002 00832023
3 00641823 1483fffa 0064082a 0c1002b2 00000000 8fbf0014 27bd0020
4 03e00008 00001025

這些機器語言對人的閱讀和理解相當的不友好。當程序越來越復雜,人們迫切需要一種簡單不易出錯的記法形式,於是人們創造了匯編語言,用簡短的詞語來助記機器操作。用MIPS R4000處理器的匯編語言重寫上面的栗子如下:

 1    addiu  sp,sp-32
 2    sw     ra,20(sp)
 3    jal    getint
 4    nop
 5    jal    getint
 6    sw     v0,28(sp)
 7    lw     a0,28(sp)
 8    move   v1,v0
 9    beq    a0,v0,D
10    slt    at,v1,a0
11 A: beq    at,zero,B
12    nop    
13    b      C
14    subu   a0,a0,v1
15 B: subu   v1,v1,a0
16 C: bne    a0,v1,A
17    slt    at,v1,a0
18 D: jal    putint
19    nop
20    lw     ra,20(sp)
21    addiu  sp,sp,32
22    jr     ra
23    move   v0,zer

對於這個栗子,閱讀和理解上明顯要比機器語言要容易得多。然而這種編碼形式計算機是不識別的,需要一種叫做“匯編器”的程序來翻譯成對應的機器的機器語言才能執行。這種一個匯編指令對應一個機器之路的關系還是顯而易見的,對於不同的計算機,則還需不同的匯編語言來編寫;這個時代的程序設計仍然是以機器為中心,程序員也許要以機器的思維來解決問題。

就如同機器語言到匯編語言的過渡一樣,程序越來越復雜、各種類型的計算機越來越多,為每一種機器都編寫程序也越來越困難、人力成本也越來越大。

根據計算機科學領域慣用的抽象原則,人們需要一個中間層來隔離某一個計算操作對具體機器的具體操作指令的這種對應關系,也就是這個中間層需要獨立於具體的機器操作。隨后人們就創造出了高級程序設計語言來做這么一個中間層,由於剝離了計算操作到具體機器操作的對應關系,但是機器具體執行的依然還是機器操作,那么也就需要一個更“高級的翻譯器”來做這項翻譯工作,這個高級的翻譯器就是現在所說的編譯器。

由於這種翻譯工作是由機器來完成的,在編譯器出現的早期時候,人們總是能夠寫出比高級語言代碼更高效的相應的匯編語言(畢竟早期的時候計算機的計算能力還一種奢侈的資源)。但是隨着程序進一步的擴大、硬件性能的提升、編譯器的優化、程序的維護成本等等變化,這種性能差異和人力成本相比慢慢也就顯得微不足道了。現在想一想,當初c++面世的時候、基於虛擬機技術的java出現時也是這么一種情況。

自從高級程序設計語言出現以后,程序設計慢慢開始從以機器為中心向以人為中心轉變。

2.編譯和解釋

按照抽象的觀點來看,高級語言的編譯和執行大致是如下的樣子:

編譯器把源程序翻譯成目標程序(典型的是機器語言程序)后就隱退了,后面的程序的運行中就不在需要編譯器的存在了。

解釋器是另外一種實現高級語言的方式:

和編譯器不同的是,解釋器一直全程守候。解釋器本身相當於一個“虛擬機”,它的“機器語言”就是源程序的高級語言。和編譯器相比,解釋器可以有更大的靈活性。它可以輕易地做到在程序運行初期來生成某一塊新的代碼,然后再后續的某一個時間去執行它;以及把一些決策推遲到運行時再去做決定。和解釋器相對應,編譯型的語言通常可以帶來較好的性能,它可以在編譯時期就把一些決策確定下來,比如一些內存布局。

雖然兩者的概念很清晰,也有較大的差異性,然而現實中有些語言是“混合型”的,流程大致如下:

如果初期階段的翻譯器比較簡單,則我們把它稱為解釋型語言;如果翻譯階段復雜,則成為編譯型語言。然而簡單和復雜本身是個形容詞,而不能可量化。完全有可能出現一個復雜的翻譯器負責中間語言程序的生成,一個復雜的虛擬機(解釋器)來執行中間語言,JAVA、.NET也正是這種實現方式。

2.1連接器和預處理器

我們所用的高級語言所寫的程序通常還需要一個庫(包含一些IO、網絡等等的操作),在編譯的時候就需要把我們寫的源程序和庫程序鏈接到一起來生成目標代碼,比如我要讀寫文件,則需要鏈接IO相關的庫程序。通常情況下目標代碼為匯編語言而不是機器語言,這種方式更有利於調試程序,也便於閱讀,更能把編譯器和機器語言文件格式的變化隔離開來。預處理器可以提供一種條件編譯的功能,比如C#中編譯條件#if DEBUG這些東西,再如C、C++中的宏機制也是屬於預編譯的范濤。

3.程序語言的設計實現以及分類

現實中語言的設計和實現總是有不可調和的矛盾,從設計角度來看總是希望一個語言能有更強大的表達能力,然而卻總是受到語言的實現制約。這根本原因大概也許是以人為中心和以機器為中心的矛盾吧,因為你的語言的執行最終還是離不開機器的執行,所以語言設計者也是不得不在這兩者中間尋求平衡。

依據現有的計算模型(運算產生結果或運算影響結果),大致分為兩大類(當然這些所謂的分類也是從不同角度得來的,如果你站在另外的角度看,或許就是另外一番景象了)說明式語言和命令式語言。從某種的角度看,說明式語言明顯要更“高級”,因為它更貼近使用者-程序員,而更遠離實現者-語言設計者。然而現在的語言還是命令式占據着統治地位,主要是因為實現的難度、性能的要求等原因制約着說明式語言的發展。上層是抽象的高級語言,下層是實現的細節,抽象層級越高,實現的難度則越大,因為你要隔離隱藏的細節越復雜。

函數式語言是說明式語言中的一個,近年它的熱度也是急劇上升來着;我們熟知的C、C++、JAVA,C#等都是屬於馮諾依曼體系的范濤,當然也是命令式語言的子集。和函數式語言中的把函數和數值作為語言的一等公民(可以賦值為給變量、作為參數傳遞、作為返回值處理)不一樣的是,馮諾依曼語言的中的基本操作是賦值語句,它們通過“副作用”去影響后續的計算結果。

腳本語言比如JS,它們一般都是擁有強大靈活度的解釋性語言,一般充當着“粘結劑”的角色。等等還有諸多的語言分類,就不在此贅述了。

總結

本篇介紹了語言的從機器語言到匯編再到高級語言的演進過程以及其發展的驅動力;以及高級語言的兩種實現方式“解釋”和“編譯”的差異;以及按照語言的計算模型進行的語言分類。因為這些都是我個人理解的一家之言,難免會有一些錯誤或者不嚴謹的地方,歡迎園友們不吝賜教。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM