最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++動態(tài)加載so/dll庫的實現(xiàn)

 更新時間:2023年07月23日 09:28:50   作者:QX0  
本文主要介紹了C++動態(tài)加載so/dll庫的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

在C++使用動態(tài)庫,(linux下是.so,windows下是.dll) 比較常見的方式是在編譯時,直接連接到程序中。但是除了這種方式外,還可以使用的動態(tài)加載的方式去使用動態(tài)庫。

兩種方式的區(qū)別

  • 在編譯時把庫連接到程序:這種方式是在編譯的時候,就確定了要鏈接的庫文件,然后通過編譯參數(shù)在鏈接時直接把動態(tài)庫的地址空間等等信息連接到程序中。程序在運行時,可以直接根據(jù)路徑去尋找動態(tài)庫,然后加載到程序中,然后運行,這種方式在日常開發(fā)中用的比較多。
  • 在程序運行時動態(tài)加載庫:這種方式是在程序運行時,通過調(diào)用系統(tǒng)函數(shù),把動態(tài)庫加載到程序中,然后執(zhí)行動態(tài)庫中的代碼。這種方式和編譯時鏈接的優(yōu)勢是可以在程序運行的過程中動態(tài)加載和卸載庫。可以在不修改源程序的前提下,使用新的庫。這種方式,比較常見的應用是程序的插件系統(tǒng)。

動態(tài)加載庫

不廢話了,直接開始上代碼

在程序運行的過程中動態(tài)加載庫,需要依賴操作系統(tǒng),所以在不同的系統(tǒng)上有不同的系統(tǒng)調(diào)用函數(shù)。

在linux 上需要用到 dlopen 函數(shù)加載庫,dlclose 函數(shù)釋放庫,dlsym 函數(shù) 查找?guī)旌瘮?shù)

需要的頭文件 #include <dlfcn.h>

在windows 上需要 LoadLibrary 宏加載庫,F(xiàn)reeLibrary 宏釋放庫,GetProcAddress 函數(shù)查找?guī)旌瘮?shù)

需要的頭文件 #include <windows.h>

基類功能

在C++中可以通過定義一個抽象類來作為所有庫的基類,所有的庫文件都實現(xiàn)這個基類,然后重寫基類的純虛函數(shù)。可以在加載到所有庫后,都可以把庫里的類作為抽象類的派生類。

先定義一個基類 base.h

#ifndef DLOAD_BASE_H
#define DLOAD_BASE_H
/**
?* 必須實現(xiàn) moduleName_create 函數(shù),來初始化對象
?* extern "C" Base *module1_create() {
?* ? ? return new Module;
?* }
?*
?* //必須實現(xiàn) moduleName_destroy 函數(shù),來回收對象
?* extern "C" void module1_destroy(Base *obj) {
?* ? ? delete obj;
?* }
?*/
class Base {
?public:
? virtual std::string readLine(const std::string &) = 0;
? virtual ~Base() = default;
};
#endif //DLOAD_BASE_H

這個基類的功能很簡單,只有一個純虛函數(shù)readLine 這個函數(shù)會傳入一個字符串,然后返回一個字符串

注釋中的哪兩個函數(shù),后面會有詳細的介紹

實現(xiàn)一個模塊

可以把一個庫看做是一個模塊,現(xiàn)在實現(xiàn)一個模塊

//簡單的模塊 例子
//轉(zhuǎn)大寫
#include <algorithm>
#include <string>
#include "../base.h"
class Module1 : public Base {
? std::string readLine(const std::string &str) override {
? ? ? std::string str2(str);
? ? ? std::transform(str.begin(), str.end(), str2.begin(), ::toupper);
? ? ? return str2;
? }
};
//必須實現(xiàn) moduleName_create 函數(shù),來初始化對象
extern "C" Base *module1_create() {
? ? return new Module1;
}
//必須實現(xiàn) moduleName_destroy 函數(shù),來回收對象
extern "C" void module1_destroy(Base *obj) {
? ? delete obj;
}

這個功能非常簡單,把傳入的字符串轉(zhuǎn)成大寫,然后返回

為什么需要 Base *module1_create() 和 void module1_destroy(Base *obj) 這兩個函數(shù)

因為在把庫加載完成后,需要使用庫里的函數(shù),但是不能直接查找C++的類,然后再初始化對象,只能在庫里完成C++對象的初始化,然后返回對象的指針。
所以需要在庫里有對應的函數(shù)來初始化對象和回收對象,所以就有了這兩個函數(shù)。

為什么要 extern "C"

因為C++有函數(shù)重載的功能,所以編譯器在編譯代碼的時候,會對函數(shù)重命名。但是對函數(shù)重命名的規(guī)則,沒有統(tǒng)一的標準,不同編譯器有不同的規(guī)則。像 module1_create 這個函數(shù)可能就被重命名成 _Z14module1_create這樣的字符串。這樣后面使用 dlsym 或者 GetProcAddress 函數(shù)查找?guī)炖锏暮瘮?shù)時,就沒法找到對應的函數(shù)了。所以使用extern "C" 讓編譯器使用C的規(guī)則來編譯這段函數(shù)

至于這兩個函數(shù)的名字 module1_create 和 module1_destroy 沒有強制的要求,但是要有一定的規(guī)范。否則在加載到庫后,沒法根據(jù)函數(shù)名查找到對應的函數(shù)。這里用到的規(guī)則是 模塊名_create 和 模塊名_destroy

加載庫

下面開始加載庫,因為在同的系統(tǒng)下,加載庫調(diào)用的函數(shù)不同,所以使用 宏來完成不用系統(tǒng)下的條件編譯,最終完成加載庫

//聲明創(chuàng)建對象的函數(shù)
typedef Base *(*create)();
//聲明回收對象的函數(shù)
typedef void (*destroy)(Base *);
//調(diào)用系統(tǒng)函數(shù),加載動態(tài)庫
#ifdef _WIN32
HINSTANCE loadLib(Base **base, const char *path, const char *funName) {
? ? auto handle = LoadLibrary(path);
? ? if (!handle) {
? ? ? ? return nullptr;
? ? }
? ? auto cr = (create) GetProcAddress(handle, funName);
? ? if (cr) {
? ? ? ? *base = cr();
? ? }
? ? return handle;
}
//調(diào)用系統(tǒng)函數(shù),卸載動態(tài)庫
void freeLib(HINSTANCE handle, Base *obj, const char *funName) {
? ? auto free = (destroy) GetProcAddress(handle, funName);
? ? if (free) {
? ? ? ? free(obj);
? ? }
? ? FreeLibrary(handle);
}
#else
void *loadLib(Base **base, const char *path, const char *funName) {
? ? auto handle = dlopen(path, RTLD_LAZY);
? ? if (!handle) {
? ? ? ? return nullptr;
? ? }
? ? auto cr = (create) dlsym(handle, funName);
? ? if (cr) {
? ? ? ? *base = cr();
? ? }
? ? return handle;
}
//調(diào)用系統(tǒng)函數(shù),卸載動態(tài)庫
void freeLib(void *handle, Base *obj, const char *funName) {
? ? auto free = (destroy) dlsym(handle, funName);
? ? if (free) {
? ? ? ? free(obj);
? ? }
? ? dlclose(handle);
}
#endif

在代碼最開始的位置,通過 typedef 聲明了兩個函數(shù)的指針,在查找到函數(shù)后,把函數(shù)強轉(zhuǎn)成對應的類型,才能在后面使用

使用庫

int main() {
? ? std::string libPath;
#ifdef _WIN32
? ? libPath = std::string("./module/libmodule1" + ".dll");
#else
? ? libPath = std::string("./module/libmodule1" + ".so");
#endif
? ? Base *module = nullptr;
? ? auto handle = loadLib(&module, libPath.c_str(), std::string("module1_create").c_str());
? ? if (!module) {
? ? ? ? std::cout << "load lib module1" << " fail" << std::endl;
? ? ? ? return 1;
? ? }
? ? std::cout << module->readLine("abc") << std::endl;
? ? return 0;
}

現(xiàn)在基本就完成了一個動態(tài)庫的動態(tài)加載過程。如果想要拓展,只要再按照這個規(guī)則,寫一個新的模塊然后加載上來就可以了。
最后放一個相對完整的動態(tài)加載的demo,github

到此這篇關于C++動態(tài)加載so/dll庫的實現(xiàn)的文章就介紹到這了,更多相關C++動態(tài)加載so/dll庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C++中類的成員函數(shù)及內(nèi)聯(lián)函數(shù)使用及說明

    C++中類的成員函數(shù)及內(nèi)聯(lián)函數(shù)使用及說明

    這篇文章主要介紹了C++中類的成員函數(shù)及內(nèi)聯(lián)函數(shù)使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C語言淺析函數(shù)的用法

    C語言淺析函數(shù)的用法

    C語言函數(shù)是用來模塊化構建程序的。如果你的功能少,你可以全都寫在mian函數(shù)中,但是當實現(xiàn)功能多的時候,如果全寫在main的函數(shù)里,不僅代碼不美觀,而且函數(shù)實現(xiàn)的時候結(jié)構復雜,代碼重復
    2022-07-07
  • C語言用封裝方法實現(xiàn)飛機大戰(zhàn)游戲

    C語言用封裝方法實現(xiàn)飛機大戰(zhàn)游戲

    這篇文章主要為大家詳細介紹了C語言用封裝方法實現(xiàn)飛機大戰(zhàn)游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • OpenCV?直方圖均衡化的實現(xiàn)原理解析

    OpenCV?直方圖均衡化的實現(xiàn)原理解析

    直方圖均衡化是通過拉伸像素強度分布范圍來增強圖像對比度的一種方法,今天通過本文給大家介紹OpenCV?直方圖均衡化的實現(xiàn)原理解析,感興趣的朋友跟隨小編一起看看吧
    2022-01-01
  • 樹存儲結(jié)構的幾種表示方法

    樹存儲結(jié)構的幾種表示方法

    今天小編就為大家分享一篇關于樹存儲結(jié)構的幾種表示方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • QT圓形圖像剪切功能實現(xiàn)

    QT圓形圖像剪切功能實現(xiàn)

    這篇文章主要介紹了QT圓形圖像剪切,實現(xiàn)代碼包括剪切代碼,完整QML源碼,C++代碼,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10
  • C++?ROS與boost:bind()使用詳解

    C++?ROS與boost:bind()使用詳解

    boost::bind是標準庫函數(shù)std::bind1st和std::bind2nd的一種泛化形式,其可以支持函數(shù)對象、函數(shù)、函數(shù)指針、成員函數(shù)指針,并且綁定任意參數(shù)到某個指定值上或者將輸入?yún)?shù)傳入任意位置,本文重點介紹下C++?ROS與boost:bind(),感興趣的朋友跟隨小編一起看看吧
    2023-01-01
  • C語言自定義類型之聯(lián)合和枚舉解讀

    C語言自定義類型之聯(lián)合和枚舉解讀

    聯(lián)合體共享內(nèi)存,大小由最大成員決定,遵循對齊規(guī)則;枚舉類型列舉可能值,提升可讀性和類型安全性,兩者在C語言中用于優(yōu)化內(nèi)存和程序效率
    2025-08-08
  • C++20 新特性 協(xié)程 Coroutines(2)

    C++20 新特性 協(xié)程 Coroutines(2)

    上篇文章簡單給大介紹了 C++20 特性 協(xié)程 Coroutines co_yield 和 co_return 那么這篇文章繼續(xù)給大家介紹C++20 的新特性協(xié)程 Coroutines co_await,需要的朋友可以參考一下
    2021-10-10
  • C語言實現(xiàn)簡易通訊錄(靜態(tài)版本)的代碼分享

    C語言實現(xiàn)簡易通訊錄(靜態(tài)版本)的代碼分享

    這篇文章主要為大家詳細介紹了如何錄音C語言實現(xiàn)一個簡易的通訊錄(靜態(tài)版本),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-10-10

最新評論

读书| 宿迁市| 南投市| 莆田市| 泊头市| 琼结县| 东丽区| 雷山县| 鹤峰县| 清苑县| 池州市| 云龙县| 大田县| 上饶县| 泗水县| 通江县| 依安县| 嘉兴市| 大悟县| 稻城县| 仁化县| 房山区| 肃宁县| 塔河县| 马边| 蒲城县| 临沧市| 科技| 通化市| 共和县| 两当县| 资中县| 社旗县| 汝城县| 孟村| 信宜市| 肥乡县| 岳普湖县| 齐齐哈尔市| 广德县| 马龙县|