靜態鏈結 庫 與動態鏈結 庫

2021-06-06 10:11:55 字數 4636 閱讀 3734

靜態鏈結與動態鏈結

簡單的說,靜態庫和應用程式編譯在一起,在任何情況下都能執行,而動態庫是動態鏈結,顧名思義就是在應用程式啟動的時候才會鏈結,所以,當使用者的系統上沒有該動態庫時,應用程式就會執行失敗。再看它們的特點:

動態庫:

1.共享:多個應用程式可以使用同乙個動態庫,啟動多個應用程式的時候,只需要將動態庫載入到記憶體一次即可;

2.開發模組好:要求設計者對功能劃分的比較好。

windows 下的靜態鏈結(庫)與動態鏈結(庫)

靜態鏈結方法:#pragma comment(lib, "test.lib") ,靜態鏈結的時候,載入**就會把程式會用到的動態**或動態**的位址確定下來

靜態庫的鏈結可以使用靜態鏈結,動態鏈結庫也可以使用這種方法鏈結導入庫

動態鏈結方法:loadlibrary()/getprocessaddress()和freelibrary(),使用這種方式的程式並不在一開始就完成動態鏈結,而是直到真正呼叫動態庫**時,引導程式才計算(被呼叫的那部分)動態**的邏輯位址,然後等到某個時候,程式又需要呼叫另外某塊動態**時,引導程式又去計算這部分**的邏輯位址,所以,這種方式使程式初始化時間較短,但執行期間的效能比不上靜態鏈結的程式。

靜態庫(static library):

函式和資料被編譯進乙個二進位制檔案(通常擴充套件名為.lib)。在使用靜態庫的情況下,在編譯鏈結可執行檔案時,鏈結器從庫中複製這些函式和資料並把它們和應用程式的其它模組組合起來建立最終的可執行檔案(.exe檔案)。

導入庫(import library):在使用動態鏈結庫的時候,往往提供兩個檔案:乙個引入庫和乙個dll。引入庫包含被dll匯出的函式和變數的符號名,dll包含實際的函式和資料。在編譯鏈結可執行檔案時,只需要鏈結引入庫,dll中的函式**和資料並不複製到可執行檔案中,在執行的時候,再去載入dll,訪問dll中匯出的函式。

在執行windows程式時,它通過乙個被稱作「動態鏈結」的程序與windows相接。乙個windows的.exe檔案擁有它使用不同動態鏈結庫的引用,所使用的函式即在那裡。當windows程式被載入到記憶體中時,程式中的呼叫被指向dll函式的入口,如果dll不在記憶體中,系統就將其載入到記憶體中。

當鏈結windows程式以產生乙個可執行檔案時,你必須鏈結由程式設計環境提供的專門的「導入庫(import library)庫」。這些導入庫包含了動態鏈結庫名稱和所有windows函式呼叫的引用資訊。鏈結程式使用該資訊在.exe檔案中構造乙個表,當引導程式時,windows使用它將呼叫轉換為windows函式。

靜態庫與導入庫的區別:導入庫和靜態庫的區別很大,他們實質是不一樣的東西。靜態庫本身就包含了實際執行**、符號表等等,而對於導入庫而言,其實際的執行**位於動態庫中,導入庫只包含了位址符號表等,確保程式找到對應函式的一些基本位址資訊。

靜態鏈結庫 檔案*.lib,動態鏈結庫 檔案*.dll。

對於靜態鏈結庫(比較簡單):首先,靜態鏈結庫的使用需要庫的開發者提供生成庫的.h標頭檔案和.lib檔案。

生成庫的.h標頭檔案中的宣告格式如下:extern "c" 函式返回型別函式名(參數列);在呼叫程式的.cpp源**檔案中如下:

#include "..\lib.h"

#pragma comment(lib,"..\\debug\\libtest.lib")

//指定與靜態庫一起鏈結

第二,因為靜態鏈結庫是將全部指令都包含入呼叫程式生成的exe檔案中。因此如果用的是靜態鏈結庫,那麼也就不存在「匯出某個函式提供給使用者使用」的情況,要想用就得全要!要不就都別要!:)

1. 靜態載入------程式靜態編譯的時候就靜態匯入dll,這樣的話就需要提供給庫使用者(c客戶)如下檔案:*.lib檔案和.dll檔案和*.h。其有2個壞處:

1 程式一開始執行就需要載入整個dll,無法引導程式就不能開始執行;

2 由於載入的是整個dll,需要耗費資源較多

其呼叫方法如下:

#include "..\lib.h"

#pragma comment(lib,"..\\debug\\libtest.lib")

但是這種方式的話可以呼叫class method.

2.動態載入-----那麼只需要提供dll檔案。

因此呼叫程式若想呼叫dll中的某個函式就要以某種形式或方式指明它到底想呼叫哪乙個函式。但是無法呼叫class method了。如果要呼叫dll中的function,需要經歷3個步驟:

handle h=loadlibrary(dllname) --> getprocaddress(h,functionname) 返回函式指標,通過函指標呼叫其function-->freelibrary(h)

例如:another.dll有乙個int add(int x,int y)函式。則完整的呼叫過程如下:

typedef int (* funptr)(int,int);//定義函式指標

funptr funptr;

handle h=loadlibrary("another.dll");

funptr=(funptr)getprocaddress(h,"add");

funptr(2,3);//2+3;

freelibrary(h);

linux下靜態鏈結(庫)與動態鏈結(庫)

庫有動態與靜態兩種,動態通常用.so為字尾,靜態用.a為字尾。 例如:libtest.so libtest.a。為了在同一系統中使用不同版本的庫,可以在庫檔名後加上版本號為字尾,但由於程式連線預設以.so為檔案字尾名。所以為了使用這些庫,通常使用建立符號連線的方式。如:

ln -s libtest.so.1.0 hello.so.1

ln -s libtest.so.1 hello.so 下面對比一下兩者:

動態庫而言:某個程式在執行中要呼叫某個動態鏈結庫函式的時候,作業系統首先會檢視所有正在執行的程式,看在記憶體裡是否已有此庫函式的拷貝了。如果有,則讓其共享那乙個拷貝;只有沒有才鏈結載入。在程式執行的時候,被呼叫的動態鏈結庫函式被安置在記憶體的某個地方,所有呼叫它的程式將指向這個**段。因此,這些**必須使用相對位址,而不是絕對位址。在編譯的時候,我們需要告訴編譯器,這些物件檔案是用來做動態鏈結庫的,所以要用位址不無關**(position independent code (pic))。注意:linux下進行連線的預設操作是首先連線動態庫,也就是說,如果同時存在靜態和動態庫,不特別指定的話,將與動態庫相連線。

1.編寫庫檔案lib_test.c 2.編寫乙個標頭檔案用於宣告我們使用的函式lib_test.h 3.用gcc編繹該檔案,可以使用任何合法的編繹引數

#ifndef _libtest_h

#define _libtest_h

gcc -c lib_test.c -o lib_test.o

void a();

#endif

#include lib_test.h

void a()

(一)靜態鏈結庫

1)用gcc編繹該檔案,可以使用任何合法的編繹引數

gcc -c lib_test.c -o lib_test.o

2) $ar crv libtest.a lib_test.o //生成靜態庫生成libtest.a

3) 在某些系統中還要為靜態庫生成乙個內容表 $ranlib libtest.a

4) 使用靜態鏈結庫

$nm libtest.a //nm工具可以列印出庫中的涉及到的所有符號,庫既可以是靜態的也可以是動態的。nm列出的符號有很多,常見的有三種,一種是在庫中被

呼叫,但並沒有在庫中定義(表明需要其他庫支援),用u表示;一種是庫中定義的函式,用t表示,這是最常見的;另外一種是所謂的"弱態」

符號,它們雖然在庫中被定義,但是可能被其他庫中的同名符號覆蓋,用w表示。

$gcc -c -i/home/******xx main.c //假設main.c要使用對應的靜態庫

$gcc -o main -l/home/******xx main.o libtest.a

說明:這裡的-i/home/******xx和-l/home/******xx 是通過-i和-l指定對應的標頭檔案和庫檔案的路徑,libtest.a就是要用的靜態庫。在main.c中要包含靜態庫的標頭檔案。

5)然後執行程式就可以看到成功了。#./main

(二)動態鏈結庫 可以依次使用下面的命令

1)$gcc -fpic -o libtest.o -c lib_test.c

2)$gcc -shared -o libtest.so libtest.o

也可以直接使用一條命令gcc -fpic -shared -o libtest.so lib_test.c

3)有兩種方法使用動態鏈結庫。

a)#gcc -o main main.c ./libtest.so

b)先#cp ./libtest /usr/lib 然後gcc -o test test.c libtest.so這時要保證這個庫所在目錄包括再path 環境變數中。

4)然後執行程式就可以看到成功了。#./main

最後說一下庫的路徑問題,

動態庫的搜尋路徑搜尋的先後順序是:

1.編譯目標**時指定的動態庫搜尋路徑;

2.環境變數ld_library_path指定的動態庫搜尋路徑;

3.配置檔案/etc/ld.so.conf中指定的動態庫搜尋路徑;//只需在在該檔案中追加一行庫所在的完整路徑如"/root/test/conf/lib"即可,然後ldconfig是修改生效。

4.預設的動態庫搜尋路徑/lib;

5.預設的動態庫搜尋路徑/usr/lib。

動態鏈結庫與靜態鏈結庫

有人會想,動態鏈結這樣麻煩,為什麼還要用呢?這裡有乙個技術問題,對這個問題的解決直接導致了動態載入的需求。問題是有些dll只在某個windows版本中存在,或某個api只在某些windows版本中被加入指定的dll。當你使用靜態鏈結的.exe試圖在不支援的windows版本上執行時,系統會彈出系統對...

動態鏈結庫與靜態鏈結庫

原貼出處 http blog.csdn.net benny5609 archive 2008 04 17 2298998.aspxs 還有參考 http msdn.microsoft.com zh cn library 1ez7dh12 v vs.100 aspxs 首先通過乙個簡單的靜態鏈結庫的例...

靜態鏈結庫與動態鏈結庫

靜態鏈結庫lib,在生成可執行檔案時,被全部嵌入到exe中,其顯式呼叫 pragma comment lib,lib 目標工程編譯鏈結之前需要將lib檔案和標頭檔案拷貝到工程目錄中。執行時不需要lib檔案。動態鏈結庫是在程式執行過程中,動態載入dll檔案中的函式來執行。因此dll檔案需要與exe檔案...