main.cpp
#include #include #include #include #include #include #include using namespace std;
typedef void(*check_func)();
void test_printa()
void test_call(string path_str)
cout << "開啟動態庫" << path_str << "成功" << endl;
dlerror();
//獲取乙個函式databasemodelcheck
if ((error = dlerror()) != null)
char *pbuff = null;
int buff_len = 0;
string err_info = "";
(*cac_func)();
if (pbuff != null)
cout << endl << endl;
//關閉動態鏈結庫
dlclose(handle);
return ; }}
int main()
print.cpp
#ifndef _print_h_
#define _print_h_
#include #include "print.h"
#include using namespace std;
#define plog print::getinstance()
class print
cout<
};extern "c" void test_print();
#endif
print.cpp
#include #include "print.h"
#include using namespace std;
using test_lib::print;
print* print::m_instance = null;
void test_print()
printa.h
#ifndef _printa_h_
#define _printa_h_
#include #include #include "printa.h"
using namespace std;
extern "c" void test_print();
#define plog print::getinstance()
class print
cout<
mapb;
float c;
};#endif
printa.h
#include #include #include "printa.h"
using namespace std;
print* print::m_instance = null;
void test_print()
編譯命令:
g++ main.cpp -o main -ldl -la -i. -l. -wl,-rpath=.
g++ -g -shared -fpic -fpermissive print.cpp -o libb.so
g++ -g -shared -fpic -fpermissive printa.cpp -o liba.so
輸出結果為:
可以看到程式只初始化了liba.so中的print物件,並且dlopen呼叫libb.so時test_print()使用的也是liba.so中的函式位址。
所以程式在初始化時只會載入乙份print物件。但是我們可以換種寫法,
將print.h中的void printa()修改為void printa(int);
重新編譯libb.so之後,執行main
可以看到plog的指標還是同乙個,但是執行printa函式的指標已經指向print.h裡的函式。第乙個成員a的位址沒變,目前沒有對記憶體進行操作,這時候記憶體已經有點混亂了,如果對記憶體進行讀寫,很可能造成堆疊錯誤,core。如果將printa()注釋掉的map.find放開,我這裡測試會卡死。另乙個專案測試會崩潰。
這個情況有點類似於函式的過載,又有點像基類呼叫子類的新增函式,都是指標指向了不在作用域範圍的位址。
問題到這已經定位出來了,具體原因還是在動態庫載入,函式指標,類指標是如何載入的。
解決方法:
可以申請乙個命名空間,將print.h中的類包括進去。這樣在呼叫的時候會重新建乙個該命名空間下的單例項,不影響使用。
後續又做了另外乙個測試;
main不引用printa.h,通過dlopen進行呼叫a,b。
編譯時不引用a,b兩個動態庫。
g++ main.cpp -o main -ldl
執行結果:
這裡顯示對每乙個單例項都初始化了一次,這裡懷疑是因為每次呼叫都會dlclose的緣故。
如果這樣編譯:
g++ main.cpp -o main -ldl -la -i. -l. -wl,-rpath=.
執行結果如下:
感覺和動態庫載入的順序有些關係。具體為什麼不太清楚,但是已經解決問題就不繼續了
dlopen動態載入動態庫
為了使程式方便擴充套件,具備通用性,可以採用外掛程式形式。採用非同步事件驅動模型,保證主程式邏輯不變,將各個業務已動態鏈結庫的形式載入進來,這就是所謂的外掛程式。linux提供了載入和處理動態鏈結庫的系統呼叫,非常方便。本文先從使用上進行總結,涉及到基本的操作方法,關於動態鏈結庫的本質及如何載入進來...
dlopen動態庫訪問
因專案需要多程序共享資源訪問.include include include typedef struct titem typedef structtbank typedef struct tbankctrl static titem g titem static tbank g tbank sta...
dlopen 和 dlsym 動態呼叫函式
dlopen 開啟乙個庫,獲取控制代碼。開啟so檔案獲取控制代碼 看作基位址 dlsym 在開啟的庫中查詢符號的值。so裡面查某個函式位址 dlclose 關閉控制代碼。dlerror 返回乙個描述最後一次呼叫dlopen dlsym,或 dlclose 的錯誤資訊的字串。import typede...