有些程式人的工作內容,只需要開發單一平臺的程式,例如許多Windows下的程式人,從開始寫程式至今,始終沒有離開過Windows的平臺。對他們來說,如何撰寫具可攜性的程式碼沒那麼重要。因為即使Windows平臺經歷過各個世代的版本變化,但總體來說,還是維持著相當不錯的向下相容性,使得這類的程式人,對於如何撰寫具有可攜性的程式碼,並不會認為是需要重視的課題。
不過,對有些程式人來說,開發跨多個平臺的應用程式這樣的工作,可以說是家常便飯。尤其現今行動裝置大行其道,許多應用程式在開發時,都會要求能夠推出支援眾多行動裝置及桌上型作業系統,例如iPhone、Windows Mobile、Android、PC Windows、甚至Mac的版本。對於這類的程式人,倘若能夠熟悉撰寫具可攜性程式碼的技巧,一定能夠提供相當大的助益。
分為原始碼和二進位元碼兩種層次
對程式碼而言,所謂的「可攜性(portability)」,指的便是當你將程式碼從某個應用環境(這邊指的應用環境通常代表的是作業系統或平臺)遷移至另一個應用環境時,現有的程式碼還能夠重複使用,毋需重新寫過。
可攜性放到不同的層次上討論,具有不同的意思。原始碼層次的可攜性代表的是同一份原始碼,搬到不同的作業系統、處理器上重新編譯之後,能夠正常執行。而二進位元碼層次的可攜性,則代表原始碼編譯出來的這一份產物,可以部署在不同的作業系統及處理器上。
相較於原始碼層次,二進位元碼層次的可攜性,無疑的強大許多。但想達成二進位元碼層次的可攜性,目前多半倚靠虛擬機器(Virtual Machine)的機制。例如,Java或.NET的軟體,便是倚靠JVM以及CLR提供二進位元碼層次的可攜性。
虛擬機器所提供的環境仍有局限
不過即使是Java或.NET,所能提供的可攜性仍然有所局限。好比J2SE上的Bytecode,無法於J2ME上執行,而.NET及.NET Compact Framework兩個平臺之間也有所差異。
這說明了,想要企求一個大一統的究極平臺,現實上有困難。桌上型的運算設備與手持式的行動運算設備,運算特性及行為模式會有一些天生的差異,不容易單靠任何一個平臺,完全解決可攜性的問題。
理論上眾多的高階語言都宣稱有原始碼可攜性的特性,那為什麼會產生可攜性的問題呢?有一些問題導因於處理器的特性,例如C程式語言,同樣標榜著原始碼層次的可攜性,但是它並沒有定義int這個整數型別的長度,在有些處理器上它是16位元長,有些處理器上是32、64 位元。
而當C程式碼假定了int型別的長度時,便會引發可攜性的問題。此外,像記憶體資料儲存方式究竟是little endian或是big endian,都會隨著所執行之處理器不同而有異。當你的程式假定了某一種方式,該處理器卻是另一種方式時,便會導致程式的行為出錯。
作業系統某種程度上也提供了可攜性
此外,可攜性有兩種意義。第一種意義下的可攜性,是所寫下的程式碼不涉及平臺問題。例如,以C語言寫作時不特別認定int型別的長度,那麼這樣的程式碼就不牽扯進會造成可攜性的問題。
而第二種意義下的可攜性,則是讓程式庫層次的程式碼「碰觸」平臺的差異性,但是透過抽象層次的包裝,讓應用層上的程式碼毋需直接接觸這些差異。這讓應用層上的程式碼具備了可攜性。
其實某種程度來說,作業系統已經為程式人隱藏了許多細節的差異,提供了某種程度的「可攜性」。怎麼說呢?舉例來說,大多數作業系統中的檔案系統,都提供了某種程度的抽象化,不論實體的儲存裝置究竟是CD-ROM、DVD-ROM、USB隨身碟、或者是硬碟、軟碟,對程式設計者來說,透過標準的檔案存取的API或系統呼叫,都能一視同仁地存取,並沒有太大的分別。
事實上,所有硬體設備的存取,全賴作業系統提供一個抽象層,程式人方能如此便利地撰寫程式。否則,即使同樣都是音效卡,各廠牌的音效卡控制方式也都不同,倘若沒有作業系統居中提供足夠抽象化的聲音控制API,那麼程式人光是在聲音控制這件事上,就會面臨「跨各種音效卡」的問題。
踏出第一步:設定想要攜帶的範圍
事實上,對程式設計而言,只要面對的事物有所差異、分別,就會導致可攜性的問題。作業系統透過API或系統呼叫,將許多細節隱藏,讓程式人能夠透過一致的介面,去面對有所差異的各種資源。
正因為作業系統提供了足夠抽象化的層次,縮小了我們必須處理的各種差異性的範圍,所以才讓我們得以將可攜性的關注重點,擺在如何跨越多種作業系統。
那麼該如何才能寫出具可攜性的程式碼呢?
想要寫出這樣的程式碼,首先要設定「想要攜帶的範圍」,也就是你希望這樣的程式碼,能夠運行於那些平臺或者作業系統。
這件事情很重要,因為可攜性是建立在抽象化層次之上,而且要足夠隱藏住所有想攜帶之平臺間差異性。
你不可能無限上綱到希望跨越全世界所有的運算平臺,它總是有一個限制的範圍,事實上,因為可攜性會為系統帶來間接層,越多層,通常對效能會造成越大的影響,有時也會增加理解的困難度。
第二步:發現目標平臺之間的共通性以及差異性
決定了「想要攜帶的範圍」,你才能夠更進一步的界定,這些目標平臺間的共通性與差異。這是撰寫具可攜性程式碼的重要步驟,你必須針對程式碼的應用範圍,找出一致的,以及它們之間的不同。這些一致的部分,代表的是不會造成問題的地方,而不同處則是代表必須抽象包裝,以遮掩諸平臺間差異的所在。
例如,倘若你只想支援所有泛Unix的作業系統,那麼對於像檔案路徑這樣子的東西,就毋需花費心思著墨。
但是對於想同時支援Windows及泛Unix作業系統的人來說,存取檔案的路徑這件事,就必須額外的包裝,因為對Windows眾作業系統來說,檔案路徑的表示方式和泛Unix家族不同。你必須意識到這樣的差異,才能針對它做事先的設計準備。
再以著名的SDL(Simple DirectMedia Layer)為例,它是個跨平臺的多媒體程式庫,支援了相當可觀的作業系統,若連非官方的版本都算進去,共計支援了20多種作業系統。
它在設計上,便是將和多媒體相關、但又存在平臺差異性的部分,諸如音效、鍵盤、滑鼠、搖桿、3D影像、2D影像等低階控制方式,予以包裝,提供一個抽象層。這使得基於SDL的應用程式,在多媒體的控制上是具有可攜性的。
設定「想要攜帶的範圍」以及「界定目標平臺間的共通性以及差異」,都是著手設計之前的準備功課,完成這兩個工作後,才能開始決定如何透過設計的技巧,解決目標平臺間的差異,藉以提供一個足夠抽象且具有一致性的層次,允許運行於其上的應用程式具備可攜性。
作者簡介─王建興 |
|
清華大學資訊工程系的博士研究生,研究興趣包括電腦網路、點對點網路、分散式網路管理、以及行動式代理人,專長則是Internet應用系統的開發。曾參與過的開發專案性質十分廣泛而且不同,從ERP、PC Game到P2P網路電話都在他的涉獵範圍之內。 |
熱門新聞
2025-01-06
2025-01-07
2025-01-08
2025-01-08
2025-01-06