1. 程式人生 > >強型別語言和弱型別語言

強型別語言和弱型別語言

 編譯型和解釋型

我們先看看編譯型,其實它和組合語言是一樣的:也是有一個負責翻譯的程式來對我們的原始碼進行轉換,生成相對應的可執行程式碼。這個過程說得專業一點,就稱為編譯(Compile),而負責編譯的程式自然就稱為編譯器(Compiler)。如果我們寫的程式程式碼都包含在一個原始檔中,那麼通常編譯之後就會直接生成一個可執行檔案,我們就可以直接運行了。但對於一個比較複雜的專案,為了方便管理,我們通常把程式碼分散在各個原始檔中,作為不同的模組來組織。這時編譯各個檔案時就會生成目標檔案(Object   file)而不是前面說的可執行檔案。一般一個原始檔的編譯都會對應一個目標檔案。這些目標檔案裡的內容基本上已經是可執行程式碼了,但由於只是整個專案的一部分,所以我們還不能直接執行。待所有的原始檔的編譯都大功告成,我們就可以最後把這些半成品的目標檔案“打包”成一個可執行檔案了,這個工作由另一個程式負責完成,由於此過程好像是把包含可執行程式碼的目標檔案連線裝配起來,所以又稱為連結(Link),而負責連結的程式就叫……就叫連結程式(Linker)。連結程式除了連結目標檔案外,可能還有各種資源,像圖示檔案啊、聲音檔案啊什麼的,還要負責去除目標檔案之間的冗餘重複程式碼,等等,所以……也是挺累的。連結完成之後,一般就可以得到我們想要的可執行檔案了。

上面我們大概地介紹了編譯型語言的特點,現在再看看解釋型。噢,從字面上看,“編譯”和“解釋”的確都有“翻譯”的意思,它們的區別則在於翻譯的時機安排不大一樣。打個比方:假如你打算閱讀一本外文書,而你不知道這門外語,那麼你可以找一名翻譯,給他足夠的時間讓他從頭到尾把整本書翻譯好,然後把書的母語版交給你閱讀;或者,你也立刻讓這名翻譯輔助你閱讀,讓他一句一句給你翻譯,如果你想往回看某個章節,他也得重新給你翻譯。

兩種方式,前者就相當於我們剛才所說的編譯型:一次把所有的程式碼轉換成機器語言,然後寫成可執行檔案;而後者就相當於我們要說的解釋型:在程式執行的前一刻,還只有源程式而沒有可執行程式;而程式每執行到源程式的某一條指令,則會有一個稱之為解釋程式的外殼程式將原始碼轉換成二進位制程式碼以供執行,總言之,就是不斷地解釋、執行、解釋、執行……所以,解釋型程式是離不開解釋程式的。像早期的BASIC就是一門經典的解釋型語言,要執行BASIC程式,就得進入BASIC環境,然後才能載入程式原始檔、執行。解釋型程式中,由於程式總是以原始碼的形式出現,因此只要有相應的直譯器,移植幾乎不成問題。編譯型程式雖然原始碼也可以移植,但前提是必須針對不同的系統分別進行編譯,對於複雜的工程來說,的確是一件不小的時間消耗,況且很可能一些細節的地方還是要修改原始碼。而且,解釋型程式省卻了編譯的步驟,修改除錯也非常方便,編輯完畢之後即可立即執行,不必像編譯型程式一樣每次進行小小改動都要耐心等待漫長的Compiling…Linking…這樣的編譯連結過程。不過凡事有利有弊,由於解釋型程式是將編譯的過程放到執行過程中,這就決定了解釋型程式註定要比編譯型慢上一大截,像幾百倍的速度差距也是不足為奇的。

編譯型與解釋型,兩者各有利弊。前者由於程式執行速度快,同等條件下對系統要求較低,因此像開發作業系統、大型應用程式、資料庫系統等時都採用它,像C/C++、Pascal/Object   Pascal(Delphi)、VB等基本都可視為編譯語言,而一些網頁尾本、伺服器指令碼及輔助開發介面這樣的對速度要求不高、對不同系統平臺間的相容性有一定要求的程式則通常使用解釋性語言,如Java、JavaScript、VBScript、Perl、Python等等。

但既然編譯型與解釋型各有優缺點又相互對立,所以一批新興的語言都有把兩者折衷起來的趨勢,例如Java語言雖然比較接近解釋型語言的特徵,但在執行之前已經預先進行一次預編譯,生成的程式碼是介於機器碼和Java原始碼之間的中介程式碼,執行的時候則由JVM(Java的虛擬機器平臺,可視為直譯器)解釋執行。它既保留了原始碼的高抽象、可移植的特點,又已經完成了對原始碼的大部分預編譯工作,所以執行起來比“純解釋型”程式要快許多。而像VB6(或者以前版本)、C#這樣的語言,雖然表面上看生成的是.exe可執行程式檔案,但VB6編譯之後實際生成的也是一種中介碼,只不過編譯器在前面安插了一段自動呼叫某個外部直譯器的程式碼(該解釋程式獨立於使用者編寫的程式,存放於系統的某個DLL檔案中,所有以VB6編譯生成的可執行程式都要用到它),以解釋執行實際的程式體。C#(以及其它.net的語言編譯器)則是生成.net目的碼,實際執行時則由.net解釋系統(就像JVM一樣,也是一個虛擬機器平臺)進行執行。當然.net目的碼已經相當“低階”,比較接近機器語言了,所以仍將其視為編譯語言,而且其可移植程度也沒有Java號稱的這麼強大,Java號稱是“一次編譯,到處執行”,而.net則是“一次編碼,到處編譯”。呵呵,當然這些都是題外話了。總之,隨著設計技術與硬體的不斷髮展,編譯型與解釋型兩種方式的界限正在不斷變得模糊。

動態語言和靜態語言

  通常我們所說的動態語言、靜態語言是指動態型別語言和靜態型別語言。

(1)動態型別語言:動態型別語言是指在執行期間才去做資料型別檢查的語言,也就是說,在用動態型別的語言程式設計時,永遠也不用給任何變數指定資料型別,該語言會在你第一次賦值給變數時,在內部將資料型別記錄下來。Python和Ruby就是一種典型的動態型別語言,其他的各種指令碼語言如VBScript也多少屬於動態型別語言。

(2)靜態型別語言:靜態型別語言與動態型別語言剛好相反,它的資料型別是在編譯其間檢查的,也就是說在寫程式時要宣告所有變數的資料型別,C/C++是靜態型別語言的典型代表,其他的靜態型別語言還有C#、JAVA等。

對於動態語言與靜態語言的區分,套用一句流行的話就是:Static typing when possible, dynamic typing when needed。

強型別定義語言和弱型別定義語言

(1)強型別定義語言:強制資料型別定義的語言。也就是說,一旦一個變數被指定了某個資料型別,如果不經過強制轉換,那麼它就永遠是這個資料型別了。舉個例子:如果你定義了一個整型變數a,那麼程式根本不可能將a當作字串型別處理。強型別定義語言是型別安全的語言。

(2)弱型別定義語言:資料型別可以被忽略的語言。它與強型別定義語言相反, 一個變數可以賦不同資料型別的值。

強型別定義語言在速度上可能略遜色於弱型別定義語言,但是強型別定義語言帶來的嚴謹效能夠有效的避免許多錯誤。另外,“這門語言是不是動態語言”與“這門語言是否型別安全”之間是完全沒有聯絡的!

例如:Python是動態語言,是強型別定義語言(型別安全的語言); VBScript是動態語言,是弱型別定義語言(型別不安全的語言); JAVA是靜態語言,是強型別定義語言(型別安全的語言)。

靜態型別定義語言

一種在編譯時,資料型別是固定的語言。大多數靜態型別定義語言強制這一點,它要求你在使用所有變數之前要宣告它們的資料型別。Java和C是靜態型別定義語言。

動態型別定義語言

一種在執行期間才去發現數據型別的語言,與靜態型別定義相反。VBScript和Python是動態型別定義的,因為它們是在第一次給一個變數賦值的時候找出它的型別的。

強型別定義語言

一種總是強制型別定義的語言。Java和Python是強制型別定義的。如果你有一個整數,如果不顯示地進行轉換,你不能將其視為一個字串。

弱型別定義語言

一種型別可以被忽略的語言,與強型別定義相反。VBScript是弱型別定義的。在VBScript中,可以將字串'12'和整數3進行連線得到字串'123',然後可以把它看成整數123,而不需要顯示轉換。但其實它們的型別沒有改變,VB只是在判斷出一個表示式含有不同型別的變數之後,自動在這些變數前加了一個clong()或(int)()這樣的轉換函式而已.能做到這一點其實是歸功於VB的編譯器的智慧化而已,這並非是VB語言本身的長處或短處.

結論:

靜態是型別編譯時判斷;動態是型別執行時判斷;強型別是型別獨立,不輕易轉化;弱型別是型別不嚴格區分,一般是隻要大小放得下,就可以轉化。這種是彙編級的觀點。面向物件的觀點並非這樣的,物件並不是大小差不多就是型別相容,而是關鍵的介面要相同才叫型別相容。

動態語言並非是弱型別,這是不等價的。恰好的,一般動態語言都是強型別語言,因為都是遵照面向物件的觀點來設計物件的。

動態語言的劣勢很明顯,就是缺少開發環境,執行效率差,當然語言設計上也不完美(靜態語言何止千萬,但c++也就一個)。

優勢也很明顯,就是編寫容易,層次高,接近自然語義。動態型別語言效率低下的原因,不在於變數的型別是動態的,而在於物件的方法是動態聯編的,在這一點上動態型別語言和Java沒什麼不同。

靜態型別語言的優勢究竟是什麼?

觀點一:靜態型別語言因為型別強制宣告,所以IDE可以做到很好的程式碼感知能力,因為有IDE的撐腰,所以開發大型系統,複雜系統比較有保障。

對於像Java來說,IDEA/Eclipse確實在程式碼感知能力上面已經非常強了,這無疑能夠增加對大型系統複雜系統的掌控能力。但是除了Java擁有這麼強的IDE武器之外,似乎其他語言從來沒有這麼強的IDE。C#的Visual Studio在GUI開發方面和Wizard方面很強,但是程式碼感知能力上和Eclipse差的不是一點半點。至於Visual C++根本就是一個編譯器而已,羞於提及Visual這個字眼。更不要說那麼多C/C++開發人員都是操起vi吭哧吭哧寫了幾十萬行程式碼呢。特別是像Linux Kernel這種幾百萬行程式碼,也就是用vi寫出來的阿,夠複雜,夠大型,夠長生命週期的吧。

觀點二:靜態語言相對比較封閉的特點,使得第三方開發包對程式碼的侵害性可以降到很低。動態語言在這點上表現的就比較差,我想大家都有過從網上下載某個JS包,然後放到專案程式碼裡發生衝突的經歷

也就是說靜態型別語言可以保障package的名稱空間分割,從而避免命名衝突,程式碼的良好隔離性。但是這個觀點也缺乏說服力。

靜態型別語言中C,VB都缺乏良好的名稱空間分割,容易產生衝突,但是並沒有影響他們做出來的系統就不夠大,不夠複雜。

而Visual C++開發的DLL版本衝突也是臭名昭著的,似乎C++的名稱空間沒有給它帶來很大的幫助。

而動態型別語言中Ruby/Python/Perl都有比較好的名稱空間,特別是Python和Perl,例如CPAN上面的第三方庫成噸成噸的,也從來沒有聽說什麼衝突的問題。

誠然像PHP,JavaScript這樣缺乏名稱空間的動態語言很容易出現問題,但是這似乎是因為他們缺乏OO機制導致的,而不是因為他們動態型別導致的吧?

說到大型系統,複雜業務邏輯系統,Google公司很多東西都是用python開發的,這也證明了動態型別語言並非不能做大型的複雜的系統。其實我個人認為:

動態型別語言,特別是高階動態型別語言,反而能夠讓人們不需要分心去考慮程式程式設計問題,而集中精力思考業務邏輯實現,即思考過程即實現過程,用DSL描述問題的過程就是程式設計的過程,這方面像UnixShell,ruby,SQL,甚至PHP都是相應領域當之無愧的DSL語言。而顯然靜態型別語言基本都不滿足這個要求。

那靜態型別語言的優勢究竟是什麼呢?我認為就是執行效率非常高。所以但凡需要關注執行效能的地方就得用靜態型別語言。其他方面似乎沒有什麼特別的優勢。

給你來個例子把

弱型別語言vbs:

 a=1

 b=a+"1"+"a" //結果是11a,這裡 a 成了字串

 c=a+1 //結果是2 ,這裡a則是數字型

強型別語言:c#

int a=2

stringb=a.ToString()+"1"+"a"

int c=a+1

看到了嗎?區分大小寫,需要實現申明型別外,一個重要的區別是,弱型別的語言的東西沒有明顯的型別,他能隨著環境的不同,自動變換型別

而強型別則沒這樣的規定,不同型別間的操作有嚴格定義,只有相同型別的變數才能操作,雖然系統也有一定的預設轉換,當絕沒有弱型別那麼隨便

ps:弱型別程式碼簡單,但因為變數沒有確定的型別,所以容易出錯!強型別程式碼複雜(比如:轉換日期顯示格式(convert.toDatetime("2007-1-108:08:08")).ToString("yyyy-MM-dd"),呵呵你可以看到這種寫法相當麻煩),但因為有嚴格定義所以不容易出錯

轉自:http://www.cnblogs.com/dzhanjie/archive/2011/07/07/2100340.html

http://blog.csdn.net/zhuangzhineng/article/details/3961886

http://hi.baidu.com/qishi1215/item/e7d5491151821b061994ec61