動態鏈結和靜態鏈結

2021-07-10 07:17:51 字數 2872 閱讀 5298

在類的習慣性用法中,我們提到:對於類中**量較多的成員函式,僅僅在標頭檔案的類中宣告成員和函式用法,而將方法封裝起來。

對於**量較大的成員函式來說,直接把**放在類中定義存在兩個問題:一是使用起來很不方便,二是破壞了資訊隱藏機制。

那麼為什麼說將**放在類中定義會破壞資訊隱藏機制呢?

實際上,對於變數和函式,一般在標頭檔案裡面都只會做乙個宣告,來告訴使用者引數的意義和函式的用法,而並不公布原始碼,利用類的封裝特性,對外只提供乙個藉口來供程式猿使用來達到非開源的目的。一般會將函式部分封裝在dll檔案中。

類檔案很多存在於標頭檔案中,方便使用者使用。但是在標頭檔案,也就是類內部,即使是出於開源的動機,也最好不要在標頭檔案(類裡面)進行實現。為什麼?我們分為兩種情況:

1、在標頭檔案中實現函式體,如果在標頭檔案中實現乙個函式體,那麼如果在多個c檔案中引用它,而且又同時編譯多個c檔案,將其生成的目標檔案連線成乙個可執行檔案,在每個引用此標頭檔案的c檔案所生成的目標檔案中,都有乙份這個函式的**,如果這段函式又沒有定義成區域性函式(工作域發生衝突),那麼連線到庫的時候,就會發現多個相同的函式,就會報錯。

2、如果在標頭檔案中定義全域性變數,並且將此全域性變數賦初值,那麼在多個引用此標頭檔案的c檔案中同樣存在相同變數名的拷貝,關鍵是此變數被賦了初值,所以編譯器就會將此變數放入data段,最終在連線階段,會在data段中存在多個相同的變數,它無法將這些變數統一成乙個變數,也就是僅為此變數分配乙個空間,而不是多份空間,假定這個變數在標頭檔案沒有賦初值,編譯器就會將之放入bss段,聯結器會對bss段的多個同名變數僅分配乙個儲存空間。

關於text段、data段、bss段的說明另見博文

那麼這些函式最後僅僅在類中宣告和告訴程式猿使用方法,那具體的實現方法放在**呢?

有兩種存放實現方法的檔案,一種是以lib為字尾的檔案,一種是以dll為字尾的檔案。

首先介紹以lib為字尾的檔案,c++中的lib檔案主要有兩類,一種是靜態的編譯鏈結,叫座靜態鏈結庫,裡面是貨真價實的函式的實現;另一種是動態的編譯鏈結,和dll一起聯用。因為有動態鏈結的lib的存在,所以並不是所有的lib檔案都是靜態鏈結的。

●如何使用生成的lib檔案

為了可以使用.lib檔案,我們需要剛剛生成的.lib檔案,以及它所對應的標頭檔案.h,因為.lib檔案無法直接訪問,且無法得知其介面,因此需要對應的標頭檔案。假設現在有乙個工程需要使用該lib檔案,首先需要在工程屬性中將.h檔案的路徑設定好,在檔案中使用#include將標頭檔案包含,然後對於lib檔案,需要在工程屬性中,設定其路徑(或者直接放在工程檔案的目錄下,因為工程查詢檔案時是以工程檔案所在路徑為相對路徑查詢),然後類似opencv一樣,在專案屬性中,linker->input中輸入要使用的lib名(或者使用program**,在檔案中用語句將其寫入(推薦)),這樣配置就結束了。

●lib檔案如何起作用

當工程在編譯的時候,系統就會將lib中的函式的實現插入到生成的exe中,從而完成其作用,因此我們知道,當lib很大的時候,最後生成的exe檔案會相當的大,因為將需要的lib都載入到了最終的exe中。

●如何生成dll檔案以及動態鏈結中的lib檔案

dll檔案被稱為動態鏈結庫。我們可以通過使用工程建立他們,在建立的時候首先建立乙個空專案,然後將輸出設定成dll,然後在主函式前使用***,意思是將該檔案函式以dll檔案匯出,然後編譯後生成了.lib檔案和dll檔案,其中的dll檔案就是動態鏈結庫,但是要注意這裡的.lib檔案就是上面所說的另一種lib檔案,不同於靜態鏈結庫的lib檔案(靜態庫的lib檔案中貨真價實的是函式的實現),該lib檔案中沒有函式的實現,而也是一些定義以及配置,真正的函式的實現存在於dll檔案中。

●如何使用動態鏈結中的lib和dll檔案

要想使用dll檔案,需要其對應的標頭檔案(.h檔案),lib以及dll,前兩者的使用方法和靜態是一樣的,後者放在exe同一目錄下就可以了。

●lib和dll的區別在ide編譯**、執行程式中的異同

1、單獨的沒有dll的lib是編譯的時候用到的,而dll是執行時用到的。無論是靜態的還是動態的,都有:如果僅僅要完成源**的編譯,僅僅需要lib。在有dll的情況下,如果要使動態鏈結的程式執行起來,只需要dll。

2、如果是有dll檔案的lib,一般是一些索引檔案,記錄了dll中函式的入口和位置(涉及記憶體位址的資訊),dll中是函式的具體內容;如果只有lib檔案,那麼這個lib檔案是靜態編譯出來,索引和實現都在其中。使用靜態編譯的lib檔案,在執行程式中不需要再掛動態庫,缺點是導致應用程式比較大,而且丟失了動態庫的靈活性,發布新版本時要發布新的應用程式才行。

3、動態鏈結的情況下,有兩個檔案:乙個是lib檔案,乙個是lib檔案。lib檔案包含被dll匯出的函式名稱和位置,dll包含實際的函式和資料,應用程式使用lib檔案鏈結到dll檔案。在應用程式的可執行檔案中,存放的不是被呼叫的函式**,而是dll中相應函式**的位址,從而節省了記憶體資源。dll和lib檔案必須隨應用程式一起發行,否則應用程式會發生錯誤。如果不能用lib檔案或者沒有lib檔案,可以用win32 api函式loadlibrary、getprocaddress裝載。

●使用lib的方法:

靜態lib中,乙個lib檔案實際上是任意個obj檔案的集合,obj檔案是cpp檔案編譯生成的。在編譯這種靜態庫工程時,根本不會遇到鏈結錯誤;即使有錯,也只會在使用這個lib的ext檔案或者dll工程裡暴露出來。

在vc中新建乙個static library型別的工程lib,加入test.cpp檔案和test.h檔案(標頭檔案內包括函式宣告),然後編譯,就生成了lib.lib檔案。

別的工程要使用這個lib有兩種方式:

(1)在project->link->object/library module中加入lib.lib檔案(先查詢工程目錄,再查詢系統lib目錄);或者在源**中加入指令#pragma comment(lib, 「lib.lib」)。

(2)將lib.lib拷入工程所在目錄,或者執行檔案生成的目錄,或者系統lib目錄中。

(3)加入相應的標頭檔案test.h

動態鏈結和靜態鏈結

庫從本質上來說是一種可執行的二進位制檔案,可以被載入到記憶體中執行,而根據鏈結時期的不同,庫又可以分為靜態庫和動態庫。靜態鏈結就是在編譯時將多個目標檔案組合在一起形成乙個可執行檔案的過程。1.空間與位址的分配過程中,首先會掃瞄所有的輸入檔案,獲得他們的各個段的長度,屬性和位置,然後將輸入檔案中所有的...

動態鏈結和靜態鏈結

作為一名c c 程式設計師,對於編譯鏈結的過程要了然於胸。首先大概介紹一下,編譯分為3步,首先對原始檔進行預處理,這個過程主要是處理一些 號定義的命令或語句 如巨集 include 預編譯指令 ifdef等 生成 i檔案 然後進行編譯,這個過程主要是進行詞法分析 語法分析和語義分析等,生成 s的彙編...

動態鏈結和靜態鏈結的區別

動態鏈結和靜態鏈結的區別 一 分別編譯與鏈結 linking 大多數高階語言都支援分別編譯,程式設計師可以顯式地把程式劃分為獨立的模組或檔案,然後每個獨立部分分別編譯。在編譯之後,由鏈結器把這些獨立的片段 稱為編譯單元 粘接到一起 想想這樣做有什麼好處?在c c 中,這些獨立的編譯單元包括obj檔案...