• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-3  評(píng)論-5  文章-13  trackbacks-0

            --------------------------------------------------------------------------------
            標(biāo)題: C++ 代碼移植要點(diǎn)
            作者: 葉飛虎
            日期: 2010.09.06
            --------------------------------------------------------------------------------

            1. 分層設(shè)計(jì)
               隔離平臺(tái)相關(guān)的代碼, 就像可測(cè)試性一樣, 可移植性也要從設(shè)計(jì)抓起。一般來(lái)說(shuō), 最上
               層和最下層都不具有良好的可移植性:
                  1). 最上層是 GUI, 大多數(shù) GUI 都不是跨平臺(tái)的, 如: Win32 SDK 和 MFC
                  2). 最下層是操作系統(tǒng) API, 大部分操作系統(tǒng) API 都是專(zhuān)用的

               如果這兩層的代碼散布在整個(gè)軟件中, 那么這個(gè)軟件的可植性將非常的差, 這是不言自
               明的。那么如何避免這種情況呢? 當(dāng)然是分層設(shè)計(jì)了:
                  1). 最底層采用 Adapter 模式, 把不同操作系統(tǒng)的 API 封裝成一套統(tǒng)一的接口(如:
                      KYLib 庫(kù)), 至于封裝成類(lèi)還是封裝成函數(shù), 要看實(shí)際情況而定。如果在開(kāi)發(fā)第
                      一個(gè)平臺(tái)時(shí)就采用 KYLib, 可以大大減少移植的工作量。

                  2). 最上層采用分離界面表現(xiàn)與內(nèi)部邏輯代碼的模式, 把大部分代碼放到內(nèi)部邏輯里
                      面, 界面僅僅是顯示和接收輸入, 即使要換一套 GUI, 工作量也不大。這同時(shí)也
                      是提高可測(cè)試性的手段之一, 當(dāng)然還有其它一些附加好處。所以即使你采用 QT
                      或者 GTK+ 等跨平臺(tái)的 GUI 設(shè)計(jì)軟件界面, 分離界面表現(xiàn)與內(nèi)部邏輯也是非常
                      有用的。


            2. 注意平臺(tái)的特性
               a. 目錄分隔符: 在Windows下用 '\\', 在Linux下用 '/'。

               b. 文本文件換行符: 在Windows下用 "\r\n", 在Linux下用 '\n'。

               c. 在 Windows 中文件名不區(qū)分大小寫(xiě)字母, 而在 Linux 中則區(qū)分大小寫(xiě)字母。

               d. 在 Windows 中線程可以 suspend 和 resume, 而在 Linux 中則不允許此操作。

               e. 在 Windows 的動(dòng)態(tài)庫(kù)中, 除非明確指明為 export 的函數(shù)外, 其它函數(shù)對(duì)外都是不
                  可見(jiàn)的。

               f. 在 Linux 的共享庫(kù)中, 所有非 static 的全局變量和函數(shù), 對(duì)外全部是可見(jiàn)的。這
                  要特別小心, 同名函數(shù)引起的問(wèn)題, 讓你查上兩天也不為過(guò)。

               g. 在 Linux 的共享庫(kù)中, 如果想綁定共享庫(kù)里的全局符號(hào)(變量, 函數(shù)和類(lèi)等等), 則
                  在鏈接共享庫(kù)的時(shí)候, 添加 gcc 選項(xiàng) -Wl,-Bsymbolic 即可。

               h. 在 Linux 的共享庫(kù)中, 如果共享庫(kù)存取主程序里定義的全局符號(hào), 鏈接主程序的時(shí)
                  候, 使用參數(shù) -Wl,--export-dynamic 即可。


            3. 最好不要使用編譯器特有的特性
               a. 像在 VC 里, 你要實(shí)現(xiàn)線程局部存儲(chǔ), 在變量前加一個(gè) __declspec( thread ) 就行
                  了, 然而盡管在 pthread 里有類(lèi)似的功能, 卻不能按這種方式實(shí)現(xiàn), 所以無(wú)法移植
                  到 Linux 下。

               b. 同樣 gcc 也有很多擴(kuò)展, 是在 VC 或者其它編譯器里所沒(méi)有的。如編譯成多線程安
                  全的選項(xiàng) -pthread, 此選項(xiàng)在編譯源程序和鏈接時(shí)使用。


            4. 數(shù)據(jù)類(lèi)型差別
               a. 在 VC 中64位整型是 __int64, 而在 Linux 中是 int64_t。

               b. 在 VC 中函數(shù)指針默認(rèn)情況下可以直接賦值給 void* 類(lèi)型變量, 而在 Linux 中則不
                  允許直接賦值, 必須使用 (void*) 強(qiáng)制轉(zhuǎn)換。

               c. 在 Windows 中的原子鎖相關(guān)函數(shù) InterlockXXX 中的參數(shù)類(lèi)型是 long*,
                  而在 Linux 中參數(shù)類(lèi)型是 int*。


            5. 調(diào)用外部庫(kù)(靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù))差異
               a. 在 VC 中調(diào)用外部庫(kù)有 .lib 支持, 若是動(dòng)態(tài)庫(kù)則直接通過(guò) .lib 關(guān)聯(lián)。

               b. 在 Linux 中調(diào)用靜態(tài)庫(kù)為 .a 文件, 庫(kù)之間的先后順序非常重要, 如 libKYLib.a
                  和 libkylin.a, 且 kylin 依賴 KYLib, 則在工程中加載庫(kù)的順序必須為: 先加載
                  libkylin.a, 再加載 libKYLib.a。

               c. 在 Linux 中調(diào)用動(dòng)態(tài)庫(kù)為 .so 文件, 如果有好幾個(gè)庫(kù), 它們之間有一些依賴關(guān)系的
                  話, 例如 X 依賴 Y, 那么你就要先加載那些被依賴的 Y, 然后加載 X。

               d. 在 Linux 中混合調(diào)用靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù), 如使用 libKYLib.a 和 libswgci32c.so, 且
                  libswgci32c.so 中使用了 libKYLib.a, 則在加載庫(kù)時(shí)必須先加載 libKYLib.a, 然
                  后再加載 libswgci32c.so。


            6. 加載動(dòng)態(tài)庫(kù)時(shí)查找路徑順序的差異
               a. Windows 庫(kù)搜索路徑和順序
                  1). 應(yīng)用程序目錄
                  2). 當(dāng)前工作目錄
                  3). 系統(tǒng)目錄 (%systemroot%, %systemroot%\system 和 %systemroot%\system32),
                      如: C:\WINNT\, C:\WINNT\system, C:\WINNT\system32
                  4). 路徑變量 (系統(tǒng)的環(huán)境變量 Path)

               b. Linux 庫(kù)搜索路徑和順序
                  1). 鏈接時(shí)指定的路徑, 如: -Wl,-rpath=./ 選項(xiàng)表示編譯時(shí) ld 路徑
                  2). 環(huán)境變量 LD_LIBRARY_PATH 指明的路徑
                  3). /etc/ld.so.cache中的函數(shù)庫(kù)列表
                  4). /lib目錄, 然后/usr/lib
                  5). 當(dāng)前工作目錄


            7. 動(dòng)態(tài)庫(kù)入口函數(shù)的差異
               a. Windows 中有 DllMain 入口函數(shù), 而 Linux 中則沒(méi)有。

               b. Linux 中有特殊函數(shù) _init 和 _fini, 主要是分別用來(lái)初始化函數(shù)庫(kù)和關(guān)閉的時(shí)候
                  做一些必要的處理, 我們可以把自己認(rèn)為需要的代碼放到這兩個(gè)函數(shù)里面, 它們分別
                  在函數(shù)庫(kù)被加載和釋放的時(shí)候被執(zhí)行。具體說(shuō), 如果一個(gè)函數(shù)庫(kù)里面有一個(gè)名字為
                  "_init" 的函數(shù)輸出, 那么在第一次通過(guò) dlopen() 函數(shù)打開(kāi)這個(gè)函數(shù)庫(kù), 或者只是
                  簡(jiǎn)單的作為共享函數(shù)庫(kù)被打開(kāi)的時(shí)候, _init 函數(shù)被自動(dòng)調(diào)用執(zhí)行。與之相對(duì)應(yīng)的就
                  是 _fini 函數(shù), 當(dāng)一個(gè)程序調(diào)用 dlclose() 去釋放對(duì)這個(gè)函數(shù)庫(kù)的引用的時(shí)候, 如
                  果該函數(shù)庫(kù)的被引用計(jì)數(shù)器為 0 了, 或者這個(gè)函數(shù)庫(kù)是作為一般的共享函數(shù)庫(kù)被使
                  用而使用它的程序正常退出的時(shí)候, _fini就會(huì)被調(diào)用執(zhí)行。

                  C語(yǔ)言定義它們的原型如下:
                  void _init(void);
                  void _fini(void);

                  當(dāng)使用你自己的 _init 和 _fini 函數(shù)時(shí), 會(huì)出現(xiàn)命名沖突, 就會(huì)得到一個(gè)
                  "multiple-definition" 的錯(cuò)誤, 編譯器提示已經(jīng)存在這個(gè)名字, 可以通過(guò)幾種方式
                  來(lái)解決:
                     1). 自定義 init 函數(shù)名字, 比如 myinit 用 -Wl, 選項(xiàng)給 ld 傳遞此名字:
                     gcc ... -Wl,-init=myinit

                     2). 當(dāng) GCC 編譯源程序時(shí), 可以使用選項(xiàng) -nostartfiles 來(lái)使共享庫(kù)不與系統(tǒng)
                         啟動(dòng)文件一起編譯
                     gcc ... -nostartfiles

                     3). 使用上面的函數(shù)或 GCC 的 -nostartfiles 選項(xiàng)并不是很好的習(xí)慣, 因?yàn)檫@
                         可能會(huì)產(chǎn)生一些意外的結(jié)果。相反, 庫(kù)應(yīng)該使用
                         __attribute__((constructor)) 和 __attribute__((destructor)) 函數(shù)屬
                         性來(lái)輸出它的構(gòu)造函數(shù)和析構(gòu)函數(shù)。如下所示:

                         void __attribute__((constructor)) x_init(void);
                         void __attribute__((destructor))  x_fini(void);

                         構(gòu)造函數(shù)會(huì)在dlopen()返回前或庫(kù)被裝載時(shí)調(diào)用;
                         析構(gòu)函數(shù)會(huì)在這樣幾種情況下被調(diào)用: dlclose() 返回前, 或 main() 返回
                         后, 或裝載庫(kù)過(guò)程中 exit() 被調(diào)用時(shí)。

               c. Linux 中的初始化和釋放函數(shù)不建議使用。

            --------------------------------------------------------------------------------

            posted on 2011-05-22 10:55 Kyee Ye 閱讀(485) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): C++類(lèi)庫(kù)KYLib
            欧美一区二区三区久久综合| 午夜精品久久影院蜜桃| 亚洲AV日韩精品久久久久久久| 亚洲午夜久久久久久久久久| 国内精品久久久久伊人av| 精品无码久久久久久国产| 亚洲人成无码久久电影网站| 久久久免费精品re6| 久久久久亚洲精品中文字幕 | 久久久久久午夜成人影院| 久久久中文字幕| 四虎国产精品成人免费久久| 色综合久久中文字幕无码| 久久99精品久久久久久不卡| 无码精品久久久天天影视| 狠狠人妻久久久久久综合蜜桃| 无码人妻久久一区二区三区免费| 99精品伊人久久久大香线蕉| 久久综合狠狠综合久久综合88 | 久久成人国产精品一区二区| 蜜臀av性久久久久蜜臀aⅴ麻豆| 久久强奷乱码老熟女网站| 久久w5ww成w人免费| 欧美日韩精品久久免费| 成人亚洲欧美久久久久| 久久99精品久久久久婷婷| 久久久这里有精品| 久久国产成人| 国产成人无码精品久久久免费| 国产精品久久久久久久久| 久久亚洲精品人成综合网| 影音先锋女人AV鲁色资源网久久| 久久亚洲AV永久无码精品| 国产精品久久久久jk制服| 欧美日韩中文字幕久久久不卡 | 久久国产精品成人影院| 亚洲AV无码久久精品狠狠爱浪潮| 国产精品久久久久久久久久影院| 欧美日韩中文字幕久久久不卡| 久久久久亚洲精品天堂久久久久久 | 国产99久久久国产精品~~牛|