一使用庫必要性
提高**重用性。
二庫的種類:
1 靜態庫
一般以*.a命名。
程式編譯時被載入,此後,只要程式不被重新編譯,靜態庫就沒有作用了(可以刪掉)。
由於靜態庫的**在編譯過程中已經被載入可執行程式,因此體積較大,如果有多個應用程式都用了同乙個靜態庫,在存放可執行程式的硬碟中就會有這個靜態庫的多份拷貝。如果他們同時在執行,那麼在記憶體中也會有這個靜態庫的多份拷貝。但是如下面提到的動態庫相比較,程式執行時間比較短,因為沒有執行時庫函式的載入。所謂「以空間換時間」。
下面我們用乙個例項說明靜態庫的程式設計和使用。
//庫函式:hellowlib.c
#include
void printhellow()
首先生成目標檔案:gcc -c printhellow.c –o printhellow.o
然後使用ar(archive)命令把目標檔案製作庫檔案:ar cqs libhello.a printhellow.o
注意庫檔名一定是lib***.a格式,不要忘了加lib作為字首。
下面我們寫乙個程式呼叫靜態庫libhello.a中的printhellow函式。
int main(int arc, char **argv)
下面編譯:gcc -o testlib testlib.c -l ./ -lhello
即可生成可執行檔案testlib。
注意上面的-l(大寫)指示庫的路徑在當前目錄下。如果沒有這個選項,就需要把庫libhello.a加入到標準路徑中。如/usr/lib中。-l(小寫)只需要跟hello,其他字元全部不要,否則出錯。
2 動態庫(共享庫)
一般以.so命名(share object)
與靜態庫不同,共享庫的**是在可執行程式執行時才載入記憶體的,在編譯過程中僅簡單的引用,因此**體積較小。與上面提到的靜態庫相比,很是節約空間。但執行時需要載入,因此執行時間相對靜態庫而言比較長。所謂「以時間換空間」。
動態鏈結的意思就是在程式裝載記憶體的時候才真正的把庫函式**鏈結進行確定它們的位址,並且就算有幾個程式同時執行,記憶體也只存在乙份函式**。
動態庫的**要實現這樣的功能,必須滿足這樣一種條件:能夠被載入到不同程序的不同位址,所以**要經過特別的編譯處理,我們把這種經過特別處理的**叫做「位置無關**(position independed code .pic)」。
位置無關**可以這樣看,記憶體中的動態**只有乙份副本,但動態庫的資料卻可能有多份。由於每乙個鏈結到動態的程序都可能會修改庫的資料,所以每當有這種情況,作業系統就複製出乙份資料副本,然後修改程序的位址空間對映,使它指向新的資料副本,這樣,程序最後修改的只是屬於自己的那份資料。
更詳細來說,某個程式的在執行中要呼叫某個動態鏈結庫函式的時候,作業系統首先會檢視所有正在執行的程式,看在記憶體裡是否已有此庫函式的拷貝了。如果有,則讓其共享那乙個拷貝;只有沒有才鏈結載入。這樣的模式雖然會帶來一些「動態鏈結」額外的開銷,卻大大的節省了系統的記憶體資源。我們所知c的標準庫就是動態鏈結庫,即系統中所有執行的程式共享著同乙個c標準庫的**段。
正如剛才所說,由於動態鏈結庫函式不會被拷貝到可執行檔案中。編譯的時編譯器只會做一些函式名之類的檢查。程式執行時,被呼叫的動態鏈結庫函式被安置在記憶體的某個地方,所有呼叫它的程式將指向這個**段。因此,這些**必須是相對位址,而不是絕對位址。在編譯的時候,我們需要告訴編譯器,這些物件檔案是用來做動態鏈結庫的,所以要用位址無關**(position independent code (pic))。
共享庫又可分為動態鏈結(dynamic linking)和動態載入(dynamic loading)兩種。
2.1 動態鏈結(dynamic linking)
在編譯程式時指定要連線的庫,然後再程式執行時一開始就將庫載入。這也稱為隱式呼叫庫函式。
示例仍然使用鋼材程式,編譯庫:
gcc -fpic -shared -o libhello.so printhellow.c
-fpic便指示了這是位址無關**,-shared指示是乙個共享庫
編譯程式,和靜態庫使用方法一樣:gcc -o testlib testlib.c -l ./ -lhello
這時候編譯成功,但我們執行testlib卻發生以下錯誤:
./testlib: error while loading shared libraries: libhello.so: cannot load shared object file: no such file or directory
顯然,程式載入時到標準路徑中找不到庫檔案。
解決辦法 1)把我們生成的庫放到標準路徑中去即可。
mv libhello.so /usr/lib
2)建立符號連線 ln -s `pwd`/libhello.so /usr/lib/libhello.so
3)將動態鏈結庫所在目錄名追加到動態鏈結庫配置檔案/etc/ld.so.conf中
pwd >> /etc/ld.so.conf
ldconfig
4)利用動態鏈結庫管理命令ldconfig,強制其搜尋指定目錄,並更新快取檔案,# ldconfig `pwd`
但是這種方法只是暫時的,如果再次執行ldconfig, 快取檔案內容可能改變,所需的動態鏈結庫可能不被系統共享了。
5)編譯時指定庫的載入路徑: gcc -o testlib testlib.c -l ./ -lhello -wl, -rpath ./
這裡, -rpath 說明了程式執行時庫的載入路徑,因為-rpath是ld命令的選項,所以gcc呼叫它時需要使用gcc的
-wl選項。
2.2 動態載入(dynamic loading)
程式不會自動載入庫,需要在程式中由程式設計師指定何時載入。系統提供了一套動態載入api以方便我們使用。
先看一下這些api: 1)
#include
void *dlopen( const char *file, int mode );
dlopen第乙個引數是共享庫的名稱,會在以下路徑中查詢指定的共享庫:
①環境變數ld_library_path中指定的
②檔案/etc/ld.so.cache中找到的庫的列表,由ldconfig命令重新整理。
③目錄usr/lib。
④目錄/lib。
⑤當前目錄。
第二個引數為開啟共享庫的方式。有兩個值
①rtld_now:將共享庫中的所有函式載入到記憶體
②rtld_lazy:稍後進行共享庫中的函式的載入,呼叫dlsym()時載入某函式 2)
char *dlerror();
用dlerror()函式測試是否開啟成功,並進行錯誤處理; 3)
void *dlsym( void *restrict handle, const char *restrict name );
用dlsym獲得函式位址,存放在乙個函式指標中,用獲得的函式指標進行函式呼叫。
4) char *dlclose( void *handle );
程式結束時用dlclose關閉開啟的動態庫,防止資源洩露。
下面是testdyn.c程式例項:
#include
#include
#include
int main(int arc, char **argv)
perr = dlerror();
if(null != perr)
/* get the address of printhellow function */
pfunc = dlsym(handle, "printhellow");
perr = dlerror();
if(null != perr)
/* call the function */
(*pfunc)();
dlclose(handle);
printf("load share library success!\n") ;
return -1; }
編譯:gcc -o testdyn testdyn.c–ldl
注意加上–ldl引數。
程式執行:
[root@vmwarelin7 fengxz]# ./testdyn
hellow,now in lib routine
load share library success!
Linux下如何讓自己的程式在開機時自動啟動
系統的服務在開機時一般都可以自動啟動,那我們程式自己寫的程式呢?windows 系統在 開始 所有程式 啟動 裡面放個快捷方式就行,那 linux 下呢?這也是乙個比較簡單的問題,有不少的方法可以解決,這裡介紹三種方法。因為是簡單介紹,所以具體細節不是很詳細,可以通過man看看相關手冊。一 etc ...
Linux下如何讓自己的程式在開機時自動啟動
系統的服務在開機時一般都可以自動啟動,那我們程式自己寫的程式呢?windows系統在 開始 所有程式 啟動 裡面放個快捷方式就行,那linux下呢?這也是乙個比較簡單的問題,有不少的方法可以解決,這裡介紹三種方法。因為是簡單介紹,所以具體細節不是很詳細,可以通過man看看相關手冊。一 etc rc....
在Linux下如何安裝mysql資料庫
rpm qa grep mysql檢查完畢發現有則需要解除安裝,執行以下命令 rpm e nodeps mysql包yum install mysql community 有提示資訊輸入y即可,安裝完畢之後啟動mysql資料庫,注意這裡的是6的啟動方式,跟7的不一樣 service mysqld s...