上一個帖子提到了"硬件體系"相關的話題,今天來說說和操作系統相關的話題 。C++跨平台開發中和OS相關的瑣事挺多,所以今天會啰嗦比較長的篇幅,請列位看官見諒 :-)
為了不繞口,以下把Linux和各種Unix統稱為Posix系統。
★文件系統(FileSystem以下簡稱FS)
剛開始搞跨平台開發的新手,多半都會碰上和FS相關的問題。所以先來聊一下FS。歸納下 來,開發中容易碰上的FS差異主要有如下幾個:目錄分隔符的差異;大小寫敏感的差異;路 徑中禁用字符的差異。
為了應對上述差異,你要注意如下幾點:
1、文件和目錄命名要規范
在給文件和目錄命名時,盡量只使用字母和數字。不要在同一個目錄下放兩個名稱相似( 名稱中只有大小寫不同,例如foo.cpp與Foo.cpp)的文件。不要使用某些OS的保留字(例如 aux、con、nul、prn)作文件名或目錄名。
補充一下,剛才說的命名,包括了源代碼文件、二進制文件和運行時創建的其它文件。
2、#include語句要規范
當你寫#include語句時,要注意使用正斜線"/"(比較通用)而不要使用反斜 線"\"(僅在Windows可用)。#include語句中的文件和目錄名要和實際名稱保持 大小寫完全一致。
3、代碼中涉及FS操作,盡量使用現成的庫
已經有很多成熟的、用於FS的第三方庫(比如boost::filesystem)。如果你的代碼涉及 到FS的操作(比如目錄遍歷),盡量使用這些第三方庫,可以幫你省不少事情。
★文本文件的回車CR/換行LF
由於幾個知名的操作系統對回車/換行的處理不一致,導致了這個煩人的問題。目前的局 面是:Windows同時使用CR和LF;Linux和大部分的Unix使用LF;蘋果的Mac系列使用CR。
對於源代碼管理,好在很多版本管理軟件(比如CVS、SVN)都會智能地處理這個問題,讓 你從代碼庫取回本地的源碼能適應本地的格式。
如果你的程序需要在運行時處理文本文件,要留意本文方式打開和二進制方式打開的區別 。另外,如果涉及跨不同系統傳輸文本文件,要考慮進行適當的處理。
★文件搜索路徑(包括搜索可執行文件和動態庫)
在Windows下,如果要執行文件或者加載動態庫,一般會搜索當前目錄;而Posix系統則不 盡然。所以如果你的應用涉及到啟動進程或加載動態庫,就要小心這個差異。
★環境變量
對於上述提到的搜索路徑問題,有些同學想通過修改PATH和LD_LIBRARY_PATH來引入當前 路徑。假如使用這種方法,建議你只修改進程級的環境變量,不要修改系統級的環境變量( 修改系統級有可能影響到同機的其它軟件,產生副作用)。
★動態庫
如果你的應用程序使用動態庫,強烈建議動態庫導出標准C風格的函數(盡量不要導出類 )。如果在Posix系統中加載動態庫,切記慎用RTLD_GLOBAL標志位。這個標志位會Enable全 局符號表,有可能會導致多個動態庫之間的符號名沖突(一旦碰到這種事,會出現匪夷所思 的運行時錯誤,極難調試)。
關於動態庫的話題比較大,限於篇幅,以後單獨寫一個帖子討論。
★服務/看守進程
如果你不清楚服務和看守進程的概念,請看維基百科(這裡和這裡)。為了敘述方便,以 下統稱服務。
由於C++開發的模塊大部分是後台模塊,經常會碰到服務的問題。編寫服務需要調用好幾 個系統相關的API,導致了與操作系統的緊密耦合,很難用一套代碼搞定。因此比較好的辦法 是抽象出一個通用的服務外殼,然後把業務邏輯代碼作為動態庫掛載到它下面。這樣的話, 至少保證了業務邏輯的代碼只需要一套;服務外殼的代碼雖然需要兩套(一個用於Windows、 一個用於Posix),但他們是業務無關的,可以很方便地重用。
★默認棧大小
不同的操作系統,棧的默認大小差別很大,從幾十KB(據說Symbian只有12K,真摳門)到 幾MB不等。因此你事先要打聽一下目標系統的默認棧大小,如果碰上像Symbian這樣摳門的, 可以考慮用編譯器選項調大。當然,養成"不在棧上定義大數組/大對象"的好習慣 也很重要,否則再大的棧也會被撐爆的。