[回到目錄]
白話C++
第5章. 基礎
總有一些知識,要在多年以後,我們才能感受得到它的力量。
5.1.從代碼到程式
這是一行代碼:
cout<< "Hello world!" << endl;
它是如何變成一段程式,從而在螢幕上打出“Hello world”呢?
從一行文字代碼,最後演變到一個硬體動作,我們無法在本收細究這一過程,但其中重要的一步卻必須理解:
進階語言寫成的程式碼,必須“轉變”成機器語言,才有可能讓機器執行——為什麼電腦只懂得機器語言?之前我們已經學習過:因為機器語言只有的0和1,可以直接轉化成硬體狀態變化,比如通電、斷電)。
〖重要〗: 我們寫的程式,真的能直接操作硬體嗎?
能直接操作硬體的PC(個人電腦)程式,已經是很早以前的事了。事實上,現在在一台個人電腦上,能直接操作硬體的,只有“作業系統”,而其它的應用程式,通常都需要通過作業系統的編程介面(API),或者在作業系統的“監管之下”,訪問硬體。
將原始碼,轉換為“機器語言”,當前存在三種常見的方法:編譯、翻譯、虛擬機器。
5.1.1.編譯
首先需要一個被稱為“編譯器”的程式;然後,將(程式員)編寫好的代碼,交給編譯器編譯,編譯結果得到一個新的應用程式。
成果是:新的應用程式也可以直接運行,不再需要編譯器,更不再需要原始碼,就可以和作業系統打交道。
圖 5-1 代碼編譯成程式,程式可以直接存取作業系統、甚至硬體
如果用自然語言的翻譯工作來比喻,那麼,編譯型程式相當於“筆譯”:假設你要和一位英國客戶打交道,你用中文寫了你要說的話,然後請一位翻譯家(編譯器),將它筆譯成英文稿,交給客戶(作業系統)。
第一、如果換了講另一種語言的客戶,我們很可能需要另請一位翻譯家——換一個作業系統,需要換一種編譯器。
第二、比現實中的翻譯還要慘的一點是,如果換一個作業系統,我們就一定要手頭有那個作業系統,才有可能編譯出可以在該作業系統上啟動並執行程式。
第
三、如果一開始只想著翻譯成英文,那麼可能用了太多的英國典故,這樣,用英文表達是一篇優美的文章;可能在翻譯到法文時,有些語句會變得彆扭,甚至有些典
故根本翻譯不了——在Windows下能編譯的C++程式,可能在Linux下編譯不了,特別是當你一開始時根本沒有想到跨平台的問題。
第
四、在最初的交流時,顯得效率很差,因為你每次都完整地表達在紙上,然後交給翻譯——程式不可能一下子就寫得100%正確,對於編譯型的程式來說,最初的
調試效率比較差,往往要反覆的改程式,然後編譯,看結果是否正確等,編譯器會嚴格地挑出你文法上的錯誤,但幾乎不能直接為你找出內容上的問題。
第一、談判完成,你的客戶就可以在任意時刻,任意地方,直接閱讀文稿,不需要經常向你為他配一位翻譯——一切正常之後,你的程式就可以獨立運行了,不再需要編譯器。
第二、既然你的客戶可以直接閱讀文稿,那通常這也就是效率最高的方法——沒錯,編譯出來的程式,不需每次都解釋一次,所以在運行效率上,具備先天優勢。
第
三、你可以盡情使用你的勘探所懂得的典故來增加的文章的精彩。比如你要舉一位英雄,對美國客戶,你可以舉華盛頓,對法國,你可以舉拿破崙。另外,因為
是筆譯,你的翻譯有的時間和精力來最佳化你文稿——這裡的意思是:因為事Crowdsourced Security Testing道要翻譯成哪個作業系統的程式,所以你可以深入挖掘出該目標作業系統的各種功
能。
5.1.2.解釋
首先需要一個被稱為“解譯器”的程式;然後將寫好的代碼,交給解譯器解釋,根據代碼的需要,由解譯器向作業系統打交道。
結果是:通常這種情況下,“解譯器”和“代碼”合起來,被叫成“程式”,但我們知道,並沒有實際可以自啟動並執行新程式產生。
圖 5-2 程式被解釋執行,只能經由解譯器和作業系統打交道
如
果用自然語言的翻譯工作來比喻,那麼,解釋型程式相當於現場“口譯”:你說上一段,然後翻譯家就立即翻譯給客戶聽。不過,比較糟糕的是,這個過程中,只記
下你的口述的內容,並不記載翻譯後的內容(包括客戶自己也不記),於是每次客戶想再瞭解一下你說過的內容,就必須找到翻譯重新翻譯。
第
一、客戶要一直帶著翻譯,較好情況下,多份文檔可以同用一個翻譯,最差情況下,每一份文檔都得配上一位翻譯,客戶身邊圍著一堆翻譯(而不是保鏢),又累
贅,又失面子——常有這種事發生:你寫一個200K的大小的“程式”,安裝時卻要帶數十兆大小的“解譯器”,你煩,你的使用者也煩。
第二、運行效率太差,太明顯了,根本不必再打比喻。
第三、口譯,相比筆譯,準確性會有所下降。你可能說著說著,直到很後面了,才發現前面說過的某句話有問題——相比編譯器的嚴格文法要求,解釋型程式往往對文法要求比較寬鬆,這有時是好事,但也有可能是壞事。(當然,也有存在既是翻譯型,又有嚴格語法檢查的程式)。
第四、因為中間時時隔著一位翻譯,因此當有特定需要時,經常會覺得像是在隔靴搔癢,使上不勁兒——“解譯器”可能事先配置了100用個功能,但當你需要第101個功能時,你就會發現它非常難以實現。
第一、因為是口譯,簡單處說上一大段再翻譯,困難處則說一句譯一句,再聽一句客戶的反饋,這個交流過程比較通暢——解釋型程式,在初期調試階段,往往效率比較高。
第二、不需要事先在特定的作業系統上編譯,這就使用解釋型程式先天具備跨平台的優勢。另外,有些需求的解釋型語言,通常會在文法實現上,及在庫功能實現上,做出封裝或剪裁,再加上為不同的作業系統定製一個解譯器,所以多數解釋型語言,都有較好的跨平台能力。
5.1.3.虛擬機器
軟
件界的“虛擬機器”有兩種:一種是針對使用者(人)的虛擬機器,比如VMware軟體,它可以在一台機器上,類比成兩台電腦,這“兩台電腦”還可以同時運行,並
且可以使用不同的作業系統。另外一種虛擬機器,是此時我們所講的,它只是針對“程式”類比出一台機器,它的目的是讓程式可以不去理會自己運行在什麼硬體,什
麼作業系統之上。
〖小提示〗:“編譯、解釋、虛擬機器”可以並列嗎?
把“虛擬機器”和“編譯、解釋”並列其實不太合理。因為在“虛擬機器”的世界裡,同樣還可以包含“編譯型”程式和“解釋型”程式兩種。不過,如果僅僅考慮最終程式是如何啟動並執行,則虛擬機器確實可以獨立為一種方法。
從中我們看到,“虛擬機器”在程式和作業系統之間,又增加了一個隔離層。在隔離層裡,代碼可以採用“編譯”的方式編譯成程式。但僅僅是編譯成“虛擬機器”的程式。
圖 5-3 代碼被“編譯”成虛擬機器裡的“程式”
虛擬機器裡的 “程式”僅可以直接存取虛擬機器資源,真正和作業系統或硬體打交道的,是虛擬機器,因此,將虛擬機器看成是一個更強的“解譯器”,也無不妥。反過來,之前一些典型的解釋型語言,比如Python,隨著其解譯器越來越強大,有時候人們也把它當作是一種“虛擬機器”。
直覺上,虛擬機器的存在,必然會帶來程式運行更加緩慢,也確實是虛擬機器很長一段時間的表現;不過,隨著虛擬機器技術的進步,程式的速度也在提高。
另外一個直覺,虛擬機器的存在,大大增強了程式的跨平台運行能力,這也正是採用虛擬機器的重要目的之一,Java的口號就是:“一次書寫,到處運行”。
有關虛擬機器的優缺點,不再羅列。
〖小提示〗:虛擬機器上的程式真的“一次書寫,到處運行”嗎?
由於不同作業系統上的虛擬機器,或者不同產家開發的虛擬機器之間,仍然存在一些差異,這些會給程式跨平台運行時,帶來一些相對隱秘的問題,因此在實際上系統進行試運行,調試,以至修改部分代碼,也是常見的事。
另一方面,類似.NET這樣的虛擬機器,由於商業利益點不同,所以它的主推者(微軟),並沒有主動推行跨平台的實現。
[回到目錄]
白話C++