動態庫的顯式調用
顯式調用的含義是代碼出現庫檔案名稱,使用者需要自己去
開啟和管理庫檔案。其要點為:
⑴把dlfcn.h系統標頭檔包含進來
⑵用dlopen函數開啟庫檔案,並指定開啟檔案
dllope的的第一個參數為共用庫的名稱,將會在下面位置尋找指定的共用庫。
①環境變數LD_LIBRARY_PATH列出的用分號間隔的所有目錄。
②檔案/etc/ld.so.cache中找到的庫的列表,由ldconfig命令重新整理。
③目錄usr/lib。
④目錄/lib。
⑤目前的目錄。
第二個參數為開啟共用庫的方式。有兩個取值
①RTLD_NOW:將共用庫中的所有函數載入到記憶體
②RTLD_LAZY:會推後共用庫中的函數的載入操作,直到調用dlsym()時方載入某函數
⑶用dlerror()函數測試是否開啟成功,並進行錯誤處理;
⑷用dlsym獲得函數地址,存放在一個函數指標中
⑸用獲得的函數指標進行函數調用。
⑹程式結束時用dlclose關閉開啟的動態庫,防止資源流失。
⑺用ldconfig工具把動態庫的路徑加到系統庫列表中
1、編寫測試檔案
//main.c 測試動態庫顯式調用的程式
#include<dlfcn.h> //用於動態庫管理的系統標頭檔
#include "myalib.h" //要把函數的標頭檔包含進來,否則編譯時間會報錯
int main(int argc,char* argv[])
{
//聲明對應的函數的函數指標
void (*pTest)();
//載入動態庫
void *pdlHandle = dlopen("libtest.so", RTLD_LAZY);
//錯誤處理
if(pdlHandle == NULL ) {
printf("Failed load library/n");
return -1;
}
char* pszErr = dlerror();
if(pszErr != NULL)
{
printf("%s/n", pszErr);
return -1;
}
//擷取函數的地址
pTest = dlsym(pdlHandle, "test");
pszErr = dlerror();
if(pszErr != NULL)
{
printf("%s/n", pszErr);
dlclose(pdlHandle);
return -1;
}
//實現函數調用
(*pTest)();
//程式結束時關閉動態庫
dlclose(pdlHandle);
return 0;
}
2、編譯測試檔案 使用-ldl選項指明產生的對象模組需要使用共用庫
gcc -o main -ldl main.c
執行完後就產生了一個main檔案
3、執行測試程式
執行 ./main
輸出
test
說明成功。
----------------------------------分割------------------------------------------
//say.c
#include <stdio.h>
int say(char **str){ printf("%s/n",str);
}
|
將say.c 產生共用庫的編譯:
gcc -o dlopen.so -shared say.c
//使用dlopen函數動態載入庫的原始碼
#include <stdio.h> #include <dlfcn.h> #include <unistd.h>
void show_help(char *msg){ if(msg == NULL){ printf("Usage:mydlopen dlopen.so say stringtosay/n"); }else{ printf("%s/n",msg); } exit(1); } int main(int ac,char ** av){
if(ac < 3){ show_help(NULL); } void *handle; //void *pfunc;
int (*pfunc)(char *str); char * filename = av[1]; char * func = av[2]; char * word = av[3]; char * error; handle = dlopen(filename,RTLD_LAZY); if(!handle){ printf("Error: handle/n"); return 1; }
pfunc = (int (*)(char *))dlsym(handle,func); if((error=dlerror()) != NULL){ printf("Error: dlsym/n"); return 2; } (*pfunc)(word);
dlclose(handle); return 0;
}
|
//編譯命令:
gcc -o mydlopen mydlopen.c -ldl
注意事項:
1.dlsym返回的指標是無類型的,要轉換的指定的函數的類型。
2.使用函數指標時的寫法: (*pfunc)(word); 不能直接寫成 pfunc(word);會段錯誤的
3.C還不支援預設參數,寫show_help時不能給msg以NULL的預設值
3.編譯時間要使用共用庫dl 其中有dlopen dlsynm dlerror dlclose 函數
使用命令:
./mydlopen ./dlopen.so say aaaabbbdddd
------------------------------------分割------------------------------------------
說明:pfunc = (int (*)(char *))dlsym(handle,func);
其中char *是將參數強轉,因為int (*pfunc)(char *str);是這樣定義的。
如果int (*pfunc)(char *str,int number);這樣定義,那麼強轉的時候應該這樣寫:
pfunc = (int (*)(char *,int))dlsym(handle,func);
--------------------------------------分割-----------------------------------------
編譯的時候的說明,比如現在的檔案分類樹如下:
1.work/
2.|--head.h
3.|--main.c
4.|--func.c
5.|--func2.c
這個時候欲將func2.c編譯成動態連結程式庫dlfunc.so,而func2.c中的函數用到了head.h和func.c裡面的變數和函數,這個時候應該使用命令:
gcc -o dlfunc.so -shared func2.c func.c -I./
這樣就產生了dlfunc.so。
然後編譯串連主程式。
gcc -o test main.c -ldl -I./
就行了。