假設你有下面的這樣乙個叫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.o
到print_date
),你會看到另乙個像上面那樣的 entry。
你如果將乙個靜態庫鏈結成可執行檔案,則會將整個庫嵌入到可執行檔案中, 這就像鏈結所有單個.o
檔案一樣。 你可以想象這可以使你的程式非常大,特別是如果你使用了很多庫(事實上絕大多數現代應用程式都是如此)。
動態或共享庫以.so
為字尾, 和它的靜態模擬一樣,是乙個大的object檔案表,指向所有編譯過的**。 你將使用cc -shared libname.so name.o
構建它, 如果用nm
檢視,你會發現動態庫與靜態庫有所不同。 在我的系統上,它包含有大約24個符號,而其中只有兩個是print_name
和printf
:
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 用於顯示文字和畫圖的各個函式 動態鏈結庫 我們再使用動態庫的時候...