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

2021-08-21 14:09:20 字數 2815 閱讀 7733

假設你有下面的這樣乙個叫name.c的c原始檔:

#include 

#include

void print_name(const

char * name)

當你編譯時,使用cc name.c生成name.o. 這個.o包含了name.c中定義的所有函式和變數的編譯後的**和資料,以及關聯名稱與實際**的索引。 如果你看一下這個索引,比如使用nm工具(在linux和許多其他unix上都可用),你會注意到兩個entry:

00000000 t print_name

u printf

上面兩行意思是:.o中儲存了兩個符號(函式或變數的名稱,但不是類、結構或任何型別的名稱)。 第乙個標記為t的符號實際上包含了它在name.o中的定義,另乙個標記為u的符號僅僅是乙個引用。 可以在此處找到print_name的**,但printf的**找不到。 當你的實際程式執行時,它將需要找到所有為引用的符號,並在其他object檔案中查詢它們的定義,以便鏈結稱為乙個完整的程式或完整的庫。 因此,object檔案是在原始檔中找到的定義,轉換成了二進位制形式,並且可用於組成完整程式。

您本可以逐個鏈結.o檔案的,但實際上你並沒有這麼做:因為一般.o檔案非常多,並且它們是一種實現細節,你實際上更傾向於將相關 object 組織到名稱極易分辨的多個包中。這些包稱為庫,有兩種形式:靜態和動態。

靜態庫(在unix中)幾乎總是以.a為字尾(例子包括libc.a,它是c核心庫,libm.a是c數學庫),依此類推。 繼續討論上面的例子,你將使用ar rc libname.a name.o構建靜態庫。 如果你用nm命令檢視libname.a,你會看到:

name.o:

00000000 t print_name

u printf

正如你所看到的那樣,libname.a基本上是乙個大的表,包含了一條可查詢到裡面的所有名字的索引。正如 object 檔案一樣,它包含了每個.o中定義的符號和它們引用的符號。 如果你要鏈結另乙個.o(例如date.oprint_date),你會看到另乙個像上面那樣的 entry。

你如果將乙個靜態庫鏈結成可執行檔案,則會將整個庫嵌入到可執行檔案中, 這就像鏈結所有單個.o檔案一樣。 你可以想象這可以使你的程式非常大,特別是如果你使用了很多庫(事實上絕大多數現代應用程式都是如此)。

動態或共享庫以.so為字尾, 和它的靜態模擬一樣,是乙個大的object檔案表,指向所有編譯過的**。 你將使用cc -shared libname.so name.o構建它, 如果用nm檢視,你會發現動態庫與靜態庫有所不同。 在我的系統上,它包含有大約24個符號,而其中只有兩個是print_nameprintf

00001498 a _dynamic

00001574 a _global_offset_table_

w _jv_registerclasses

00001488 d __ctor_end__

00001484 d __ctor_list__

00001490 d __dtor_end__

0000148c d __dtor_list__

00000480 r __frame_end__

00001494 d __jcr_end__

00001494 d __jcr_list__

00001590 a __bss_start

w __cxa_finalize@@glibc_2.1.3

00000420 t __do_global_ctors_aux

00000360 t __do_global_dtors_aux

00001588 d __dso_handle

w __gmon_start__

000003f7 t __i686.get_pc_thunk.bx

00001590 a _edata

00001594 a _end

00000454 t _fini

000002f8 t _init

00001590 b completed.5843

000003c0 t frame_dummy

0000158c d p.5841

000003fc t print_name

u printf@@glibc_2.0

共享庫與靜態庫有乙個非常重要的區別:共享庫不會將自身嵌入到最終的可執行檔案中, 相反,可執行檔案包含了對已解析的共享庫的乙個引用,是在執行時,而不是在鏈結時。

使用共享庫有許多優點:

還有下面的這些缺點:

(如果你想一想,這些就是程式使用或不使用引用和指標,而不是直接將類的物件嵌入到其他物件中的原因。這個模擬非常直接。)

ok,已經講了很多細節,跳過的也很多,比如鏈結過程實際上是如何工作的, 我希望你不需要澄清就看得懂。

[1]

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

靜態鏈結庫和動態鏈結庫的區別 一 靜態鏈結庫 預編譯 編譯 彙編 鏈結 linux 生成目標檔案 g c source.cpp o source.o 打包成靜態鏈結庫 ar crv source.a source.o 使用靜態鏈結庫 g test.cpp l靜態鏈結庫目錄 l靜態鏈結庫名稱沒有字尾 ...

C 靜態鏈結庫和動態鏈結庫

專案 屬性 c c 附加包含目錄 填寫附加標頭檔案所在目錄 分號間隔多項 專案 屬性 鏈結器 常規 附加庫目錄 填寫附加依賴庫所在目錄 分號間隔多項 專案 屬性 鏈結器 輸入 附加依賴項 填寫附加依賴庫的名字.lib 空格或分號間隔多項 2 dynamic link library 的縮寫形式,dl...

靜態鏈結庫和動態鏈結庫

其實再vc中,我們所用得所有api函式都封裝再下列三個dll檔案中 kernel32.dll 用於管理記憶體,程序和執行緒得各個函式 user32.dll 用於執行使用者介面任務,如視窗的建立和訊息的傳遞的各個函式 gdi32.dll 用於顯示文字和畫圖的各個函式 動態鏈結庫 我們再使用動態庫的時候...