一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

C 靜態(tài)庫與動態(tài)庫(比較透徹)

 補丁牛仔褲 2023-03-15 發(fā)布于浙江

這次分享的宗旨是——讓大家學(xué)會創(chuàng)建與使用靜態(tài)庫、動態(tài)庫,知道靜態(tài)庫與動態(tài)庫的區(qū)別,知道使用的時候如何選擇。這里不深入介紹靜態(tài)庫、動態(tài)庫的底層格式,內(nèi)存布局等,有興趣的同學(xué),推薦一本書《程序員的自我修養(yǎng)——鏈接、裝載與庫》。

1、一個程序從源文件編譯生成可執(zhí)行文件的步驟:

預(yù)編譯 -->  編譯 -->  匯編 --> 鏈接

(1)預(yù)編譯,即預(yù)處理,主要處理在源代碼文件中以“#”開始的預(yù)編譯指令,如宏展開、處理條件編譯指令、處理#include指令等。

(2)編譯過程就是把預(yù)處理完的文件進行一系列詞法分析、語法分析、語義分析以及優(yōu)化后生成相應(yīng)的匯編代碼文件。

(3)匯編是將匯編代碼轉(zhuǎn)變成二進制文件。

(4)鏈接將二進制文件鏈接成一個可執(zhí)行的命令,主要是把分散的數(shù)據(jù)和代碼收集并合成一個單一的可加載并可執(zhí)行的的文件。鏈接可以發(fā)生在代碼靜態(tài)編譯、程序被加載時以及程序執(zhí)行時。鏈接過程的主要工作是符號解析和重定位。

2、庫 

庫是一組目標(biāo)文件的包,就是一些最常用的代碼編譯成目標(biāo)文件后打包存放。而最常見的庫就是運行時庫(Runtime Library),如C運行庫CRT.

庫一般分為兩種:靜態(tài)庫(.a 、.lib)動態(tài)庫(.so 、.dll )所謂靜態(tài)、動態(tài)是指鏈接過程。 

3、靜態(tài)庫與動態(tài)庫

區(qū)別:

(1)lib是編譯時用到的,dll是運行時用到的。如果要完成源代碼的編譯,只需要lib;如果要使動態(tài)鏈接的程序運行起來,只需要dll。
(2)如果有dll文件,那么lib一般是一些索引信息,記錄了dll中函數(shù)的入口和位置,dll中是函數(shù)的具體內(nèi)容;如果只有l(wèi)ib文件,那么這個lib文件是靜態(tài)編譯出來的,索引和實現(xiàn)都在其中。使用靜態(tài)編譯的lib文件,在運行程序時不需要再掛動態(tài)庫,缺點是導(dǎo)致應(yīng)用程序比較大,而且失去了動態(tài)庫的靈活性,發(fā)布新版本時要發(fā)布新的應(yīng)用程序才行。
(3)動態(tài)鏈接的情況下,有兩個文件:一個是LIB文件,一個是DLL文件。LIB包含被DLL導(dǎo)出的函數(shù)名稱和位置,DLL包含實際的函數(shù)和數(shù)據(jù),應(yīng)用程序使用LIB文件鏈接到DLL文件。在應(yīng)用程序的可執(zhí)行文件中,存放的不是被調(diào)用的函數(shù)代碼,而是DLL中相應(yīng)函數(shù)代碼的地址,從而節(jié)省了內(nèi)存資源。DLL和LIB文件必須隨應(yīng)用程序一起發(fā)行,否則應(yīng)用程序會產(chǎn)生錯誤。如果不想用lib文件或者沒有l(wèi)ib文件,可以用WIN32 API函數(shù)LoadLibrary、GetProcAddress裝載。

------這里主要講動態(tài)庫的優(yōu)點特性。--------

靜態(tài)庫:函數(shù)和數(shù)據(jù)被編譯進一個二進制文件(通常擴展名為.LIB)。在使用靜態(tài)庫的情況下,在編譯鏈接可執(zhí)行文件時,鏈接器從庫中復(fù)制這些函數(shù)和數(shù)據(jù)并把它們和應(yīng)用程序的其它模塊組合起來創(chuàng)建最終的可執(zhí)行文件(.EXE文件)。
在使用動態(tài)庫的時候,往往提供兩個文件:一個引入庫和一個DLL。引入庫包含被DLL導(dǎo)出的函數(shù)和變量的符號名,DLL包含實際的函數(shù)和數(shù)據(jù)。在編譯鏈接可執(zhí)行文件時,只需要鏈接引入庫,DLL中的函數(shù)代碼和數(shù)據(jù)并不復(fù)制到可執(zhí)行文件中,在運行的時候,再去加載DLL,訪問DLL中導(dǎo)出的函數(shù)。

靜態(tài)庫有兩個重大缺點:

1)空間浪費

2)靜態(tài)鏈接對程序的更新、部署和發(fā)布會帶來很多麻煩。一旦程序中有任何模塊更新,整個程序就要重新鏈接,發(fā)布給用戶。

動態(tài)鏈接的基本思想:把程序按照模塊拆分成各個相對獨立的部分,在程序運行時才將它們鏈接在一起形成一個完整的程序,而不是想靜態(tài)鏈接一樣把所有的程序模塊都鏈接成一個單獨的可執(zhí)行文件。

特點:

1)代碼共享,所有引用該動態(tài)庫的可執(zhí)行目標(biāo)文件共享一份相同的代碼與數(shù)據(jù)。

2)程序升級方便,應(yīng)用程序不需要重新鏈接新版本的動態(tài)庫來升級,理論上只要簡單地將舊的目標(biāo)文件覆蓋掉。

3)在運行時可以動態(tài)地選擇加載各種應(yīng)用程序模塊


什么是庫

庫是寫好的現(xiàn)有的,成熟的,可以復(fù)用的代碼。現(xiàn)實中每個程序都要依賴很多基礎(chǔ)的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。

本質(zhì)上來說庫是一種可執(zhí)行代碼的二進制形式,可以被操作系統(tǒng)載入內(nèi)存執(zhí)行。庫有兩種:靜態(tài)庫(.a.lib)和動態(tài)庫(.so、.dll)。

所謂靜態(tài)、動態(tài)是指鏈接?;仡櫼幌?,將一個程序編譯成可執(zhí)行程序的步驟:

圖:編譯過程

靜態(tài)庫

之所以成為【靜態(tài)庫】,是因為在鏈接階段,會將匯編生成的目標(biāo)文件.o與引用到的庫一起鏈接打包到可執(zhí)行文件中。因此對應(yīng)的鏈接方式稱為靜態(tài)鏈接。

試想一下,靜態(tài)庫與匯編生成的目標(biāo)文件一起鏈接為可執(zhí)行文件,那么靜態(tài)庫必定跟.o文件格式相似。其實一個靜態(tài)庫可以簡單看成是一組目標(biāo)文件(.o/.obj文件)的集合,即很多目標(biāo)文件經(jīng)過壓縮打包后形成的一個文件。靜態(tài)庫特點總結(jié):

l  靜態(tài)庫對函數(shù)庫的鏈接是放在編譯時期完成的。

l  程序在運行時與函數(shù)庫再無瓜葛,移植方便。

l  浪費空間和資源,因為所有相關(guān)的目標(biāo)文件與牽涉到的函數(shù)庫被鏈接合成一個可執(zhí)行文件。

下面編寫一些簡單的四則運算C++類,將其編譯成靜態(tài)庫給他人用,頭文件如下所示:

StaticMath.h頭文件

#pragma once

class StaticMath

{

public:

    StaticMath(void);

    ~StaticMath(void);

    static double add(double a, double b);//加法

    static double sub(double a, double b);//減法

    static double mul(double a, double b);//乘法

    static double div(double a, double b);//除法

    void print();

};

Linux下使用ar工具、Windowsvs使用lib.exe,將目標(biāo)文件壓縮到一起,并且對其進行編號和索引,以便于查找和檢索。一般創(chuàng)建靜態(tài)庫的步驟如圖所示:

圖:創(chuàng)建靜態(tài)庫過程

Linux下創(chuàng)建與使用靜態(tài)庫

Linux靜態(tài)庫命名規(guī)則

Linux靜態(tài)庫命名規(guī)范,必須是'lib[your_library_name].a'lib為前綴,中間是靜態(tài)庫名,擴展名為.a。

創(chuàng)建靜態(tài)庫(.a

通過上面的流程可以知道,Linux創(chuàng)建靜態(tài)庫過程如下:

l  首先,將代碼文件編譯成目標(biāo)文件.oStaticMath.o

g++ -c StaticMath.cpp

注意帶參數(shù)-c,否則直接編譯為可執(zhí)行文件

l  然后,通過ar工具將目標(biāo)文件打包成.a靜態(tài)庫文件

ar -crv libstaticmath.a StaticMath.o

生成靜態(tài)庫libstaticmath.a。

大一點的項目會編寫makefile文件(CMake等等工程管理工具)來生成靜態(tài)庫,輸入多個命令太麻煩了。

使用靜態(tài)庫

編寫使用上面創(chuàng)建的靜態(tài)庫的測試代碼:

測試代碼:

#include 'StaticMath.h'

#include <iostream>

using namespace std;

int main(int argccharargv[])

{

    double a = 10;

    double b = 2;

    cout << 'a + b = ' << StaticMath::add(a, b) << endl;

    cout << 'a - b = ' << StaticMath::sub(a, b) << endl;

    cout << 'a * b = ' << StaticMath::mul(a, b) << endl;

    cout << 'a / b = ' << StaticMath::div(a, b) << endl;

    StaticMath sm;

    sm.print();

    system('pause');

    return 0;

}

Linux下使用靜態(tài)庫,只需要在編譯的時候,指定靜態(tài)庫的搜索路徑(-L選項)、指定靜態(tài)庫名(不需要lib前綴和.a后綴,-l選項)。

# g++ TestStaticLibrary.cpp -L../StaticLibrary -lstaticmath

l  -L:表示要連接的庫所在目錄

l  -l:指定鏈接時需要的動態(tài)庫,編譯器查找動態(tài)連接庫時有隱含的命名規(guī)則,即在給出的名字前面加上lib,后面加上.a.so來確定庫的名稱。

Windows下創(chuàng)建與使用靜態(tài)庫

創(chuàng)建靜態(tài)庫(.lib

如果是使用VS命令行生成靜態(tài)庫,也是分兩個步驟來生成程序:

l  首先,通過使用帶編譯器選項 /c  Cl.exe 編譯代碼 (cl /c StaticMath.cpp),創(chuàng)建名為“StaticMath.obj”的目標(biāo)文件。

l  然后,使用庫管理器 Lib.exe 鏈接代碼 (lib StaticMath.obj),創(chuàng)建靜態(tài)庫StaticMath.lib

當(dāng)然,我們一般不這么用,使用VS工程設(shè)置更方便。創(chuàng)建win32控制臺程序時,勾選靜態(tài)庫類型;打開工程屬性面板è配置屬性è常規(guī),配置類型選擇靜態(tài)庫。

圖:vs靜態(tài)庫項目屬性設(shè)置

Build項目即可生成靜態(tài)庫。

使用靜態(tài)庫

測試代碼Linux下面的一樣。有3種使用方法:

方法一:

VS中使用靜態(tài)庫方法:

l  工程屬性面板è通用屬性è “框架和引用è添加引用,將顯示添加引用對話框。 “項目選項卡列出了當(dāng)前解決方案中的各個項目以及可以引用的所有庫。 項目選項卡中,選擇 StaticLibrary。 單擊確定。

l  添加StaticMath.h 頭文件目錄,必須修改包含目錄路徑。打開工程屬性面板è配置屬性è “C/C++”è” 常規(guī),在附加包含目錄屬性值中,鍵入StaticMath.h 頭文件所在目錄的路徑或瀏覽至該目錄。

編譯運行OK。

圖:靜態(tài)庫測試結(jié)果(vs

如果引用的靜態(tài)庫不是在同一解決方案下的子工程,而是使用第三方提供的靜態(tài)庫lib和頭文件,上面的方法設(shè)置不了。還有2中方法設(shè)置都可行。

方法二:

打開工程屬性面板è配置屬性è “鏈接器è命令行,輸入靜態(tài)庫的完整路徑即可。

方法三:

l  屬性面板è配置屬性è “鏈接器è常規(guī),附加依賴庫目錄中輸入,靜態(tài)庫所在目錄;

l  屬性面板è配置屬性è “鏈接器è輸入,附加依賴庫中輸入靜態(tài)庫名StaticLibrary.lib。

動態(tài)庫

通過上面的介紹發(fā)現(xiàn)靜態(tài)庫,容易使用和理解,也達(dá)到了代碼復(fù)用的目的,那為什么還需要動態(tài)庫呢?

為什么還需要動態(tài)庫?

為什么需要動態(tài)庫,其實也是靜態(tài)庫的特點導(dǎo)致。

l  空間浪費是靜態(tài)庫的一個問題。

l  另一個問題是靜態(tài)庫對程序的更新、部署和發(fā)布頁會帶來麻煩。如果靜態(tài)庫liba.lib更新了,所以使用它的應(yīng)用程序都需要重新編譯、發(fā)布給用戶(對于玩家來說,可能是一個很小的改動,卻導(dǎo)致整個程序重新下載,全量更新)。

動態(tài)庫在程序編譯時并不會被連接到目標(biāo)代碼中,而是在程序運行是才被載入。不同的應(yīng)用程序如果調(diào)用相同的庫,那么在內(nèi)存里只需要有一份該共享庫的實例,規(guī)避了空間浪費問題。動態(tài)庫在程序運行是才被載入,也解決了靜態(tài)庫對程序的更新、部署和發(fā)布頁會帶來麻煩。用戶只需要更新動態(tài)庫即可,增量更新。

動態(tài)庫特點總結(jié):

l  動態(tài)庫把對一些庫函數(shù)的鏈接載入推遲到程序運行的時期。

l  可以實現(xiàn)進程之間的資源共享。(因此動態(tài)庫也稱為共享庫)

l  將一些程序升級變得簡單。

l  甚至可以真正做到鏈接載入完全由程序員在程序代碼中控制(顯示調(diào)用)。

WindowLinux執(zhí)行文件格式不同,在創(chuàng)建動態(tài)庫的時候有一些差異。

l  Windows系統(tǒng)下的執(zhí)行文件格式是PE格式,動態(tài)庫需要一個DllMain函數(shù)做出初始化的入口,通常在導(dǎo)出函數(shù)的聲明時需要有_declspec(dllexport)關(guān)鍵字。

l  Linuxgcc編譯的執(zhí)行文件默認(rèn)是ELF格式,不需要初始化入口,亦不需要函數(shù)做特別的聲明,編寫比較方便。

與創(chuàng)建靜態(tài)庫不同的是,不需要打包工具(arlib.exe),直接使用編譯器即可創(chuàng)建動態(tài)庫。

Linux下創(chuàng)建與使用動態(tài)庫

linux動態(tài)庫的命名規(guī)則

動態(tài)鏈接庫的名字形式為 libxxx.so,前綴是lib,后綴名為“.so”。

l  針對于實際庫文件,每個共享庫都有個特殊的名字“soname”。在程序啟動后,程序通過這個名字來告訴動態(tài)加載器該載入哪個共享庫。

l  在文件系統(tǒng)中,soname僅是一個鏈接到實際動態(tài)庫的鏈接。對于動態(tài)庫而言,每個庫實際上都有另一個名字給編譯器來用。它是一個指向?qū)嶋H庫鏡像文件的鏈接文件(lib+soname+.so)。

創(chuàng)建動態(tài)庫(.so

編寫四則運算動態(tài)庫代碼:

DynamicMath.h頭文件

#pragma once

class DynamicMath

{

public:

        DynamicMath(void);

        ~DynamicMath(void);

        static double add(double a, double b);//?ó·¨

        static double sub(double a, double b);//??·¨

        static double mul(double a, double b);//3?·¨

        static double div(double a, double b);//3y·¨

        void print();

};

l  首先,生成目標(biāo)文件,此時要加編譯器選項-fpic

g++ -fPIC -c DynamicMath.cpp

-fPIC 創(chuàng)建與地址無關(guān)的編譯程序(picposition independent code),是為了能夠在多個應(yīng)用程序間共享。

l  然后,生成動態(tài)庫,此時要加鏈接器選項-shared

g++ -shared -o libdynmath.so DynamicMath.o

-shared指定生成動態(tài)鏈接庫。

其實上面兩個步驟可以合并為一個命令:

g++ -fPIC -shared -o libdynmath.so DynamicMath.cpp

使用動態(tài)庫

編寫使用動態(tài)庫的測試代碼:

測試代碼:

#include '../DynamicLibrary/DynamicMath.h'

#include <iostream>

using namespace std;

int main(int argc, char* argv[])

{

    double a = 10;

    double b = 2;

    cout << 'a + b = ' << DynamicMath::add(a, b) << endl;

    cout << 'a - b = ' << DynamicMath::sub(a, b) << endl;

    cout << 'a * b = ' << DynamicMath::mul(a, b) << endl;

    cout << 'a / b = ' << DynamicMath::div(a, b) << endl;

    DynamicMath dyn;

    dyn.print();

    return 0;

}

引用動態(tài)庫編譯成可執(zhí)行文件(跟靜態(tài)庫方式一樣):

g++ TestDynamicLibrary.cpp -L../DynamicLibrary -ldynmath

然后運行:./a.out,發(fā)現(xiàn)竟然報錯了!??!

可能大家會猜測,是因為動態(tài)庫跟測試程序不是一個目錄,那我們驗證下是否如此:

發(fā)現(xiàn)還是報錯!??!那么,在執(zhí)行的時候是如何定位共享庫文件的呢?

1)        當(dāng)系統(tǒng)加載可執(zhí)行代碼時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑。此時就需要系統(tǒng)動態(tài)載入器(dynamic linker/loader)。

2)        對于elf格式的可執(zhí)行程序,是由ld-linux.so*來完成的,它先后搜索elf文件的 DT_RPATH段—環(huán)境變量LD_LIBRARY_PATH/etc/ld.so.cache文件列表—/lib/,/usr/lib 目錄找到庫文件后將其載入內(nèi)存。

如何讓系統(tǒng)能夠找到它:

l  如果安裝在/lib或者/usr/lib下,那么ld默認(rèn)能夠找到,無需其他操作。

l  如果安裝在其他目錄,需要將其添加到/etc/ld.so.cache文件中,步驟如下:

n  編輯/etc/ld.so.conf文件,加入庫文件所在目錄的路徑

n  運行ldconfig ,該命令會重建/etc/ld.so.cache文件

我們將創(chuàng)建的動態(tài)庫復(fù)制到/usr/lib下面,然后運行測試程序。

Windows下創(chuàng)建與使用動態(tài)庫

創(chuàng)建動態(tài)庫(.dll

Linux相比,在Windows系統(tǒng)下創(chuàng)建動態(tài)庫要稍微麻煩一些。首先,需要一個DllMain函數(shù)做出初始化的入口(創(chuàng)建win32控制臺程序時,勾選DLL類型會自動生成這個文件):

dllmain.cpp入口文件

// dllmain.cpp : Defines the entry point for the DLL application.

#include 'stdafx.h'

BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                     )

{

    switch (ul_reason_for_call)

    {

    case DLL_PROCESS_ATTACH:

    case DLL_THREAD_ATTACH:

    case DLL_THREAD_DETACH:

    case DLL_PROCESS_DETACH:

        break;

    }

    return TRUE;

}

通常在導(dǎo)出函數(shù)的聲明時需要有_declspec(dllexport)關(guān)鍵字:

DynamicMath.h頭文件

#pragma once

class DynamicMath

{

public:

    __declspec(dllexport) DynamicMath(void);

    __declspec(dllexport) ~DynamicMath(void);

    static __declspec(dllexportdouble add(double a, double b);//加法

    static __declspec(dllexportdouble sub(double a, double b);//減法

    static __declspec(dllexportdouble mul(double a, double b);//乘法

    static __declspec(dllexportdouble div(double a, double b);//除法

    __declspec(dllexportvoid print();

};

生成動態(tài)庫需要設(shè)置工程屬性,打開工程屬性面板è配置屬性è常規(guī),配置類型選擇動態(tài)庫。

圖:v動態(tài)庫項目屬性設(shè)置

Build項目即可生成動態(tài)庫。

使用動態(tài)庫

創(chuàng)建win32控制臺測試程序:

TestDynamicLibrary.cpp測試程序

#include 'stdafx.h'

#include 'DynamicMath.h'

#include <iostream>

using namespace std;

int _tmain(int argc_TCHARargv[])

{

    double a = 10;

    double b = 2;

    cout << 'a + b = ' << DynamicMath::add(a, b) << endl;

    cout << 'a - b = ' << DynamicMath::sub(a, b) << endl;

    cout << 'a * b = ' << DynamicMath::mul(a, b) << endl;

    cout << 'a / b = ' << DynamicMath::div(a, b) << endl;

    DynamicMath dyn;

    dyn.print();

    system('pause');

    return 0;

}

方法一:

l  工程屬性面板è通用屬性è “框架和引用è添加引用,將顯示添加引用對話框。項目選項卡列出了當(dāng)前解決方案中的各個項目以及可以引用的所有庫。 項目選項卡中,選擇 DynamicLibrary。 單擊確定。

l  添加DynamicMath.h 頭文件目錄,必須修改包含目錄路徑。打開工程屬性面板è配置屬性è “C/C++”è” 常規(guī),在附加包含目錄屬性值中,鍵入DynamicMath.h 頭文件所在目錄的路徑或瀏覽至該目錄。

編譯運行OK。

圖:動態(tài)庫測試結(jié)果(vs

方法二:

l  屬性面板è配置屬性è “鏈接器è常規(guī),附加依賴庫目錄中輸入,動態(tài)庫所在目錄;

l  屬性面板è配置屬性è “鏈接器è輸入,附加依賴庫中輸入動態(tài)庫編譯出來的DynamicLibrary.lib

這里可能大家有個疑問,動態(tài)庫怎么還有一個DynamicLibrary.lib文件?即無論是靜態(tài)鏈接庫還是動態(tài)鏈接庫,最后都有lib文件,那么兩者區(qū)別是什么呢?其實,兩個是完全不一樣的東西。

StaticLibrary.lib的大小為190KB,DynamicLibrary.lib的大小為3KB,靜態(tài)庫對應(yīng)的lib文件叫靜態(tài)庫,動態(tài)庫對應(yīng)的lib文件叫【導(dǎo)入庫】。實際上靜態(tài)庫本身就包含了實際執(zhí)行代碼、符號表等等,而對于導(dǎo)入庫而言,其實際的執(zhí)行代碼位于動態(tài)庫中,導(dǎo)入庫只包含了地址符號表等,確保程序找到對應(yīng)函數(shù)的一些基本地址信息

動態(tài)庫的顯式調(diào)用

上面介紹的動態(tài)庫使用方法和靜態(tài)庫類似屬于隱式調(diào)用,編譯的時候指定相應(yīng)的庫和查找路徑。其實,動態(tài)庫還可以顯式調(diào)用。【在C語言中】,顯示調(diào)用一個動態(tài)庫輕而易舉!

Linux下顯式調(diào)用動態(tài)庫

#include <dlfcn.h>,提供了下面幾個接口:

l  void * dlopen( const char * pathname, int mode ):函數(shù)以指定模式打開指定的動態(tài)連接庫文件,并返回一個句柄給調(diào)用進程。

l  void* dlsym(void* handle,const char* symbol)dlsym根據(jù)動態(tài)鏈接庫操作句柄(pHandle)與符號(symbol),返回符號對應(yīng)的地址。使用這個函數(shù)不但可以獲取函數(shù)地址,也可以獲取變量地址。

l  int dlclose (void *handle)dlclose用于關(guān)閉指定句柄的動態(tài)鏈接庫,只有當(dāng)此動態(tài)鏈接庫的使用計數(shù)為0,才會真正被系統(tǒng)卸載。

l  const char *dlerror(void):當(dāng)動態(tài)鏈接庫操作函數(shù)執(zhí)行失敗時,dlerror可以返回出錯信息,返回值為NULL時表示操作函數(shù)執(zhí)行成功。

Windows下顯式調(diào)用動態(tài)庫

應(yīng)用程序必須進行函數(shù)調(diào)用以在運行時顯式加載 DLL。為顯式鏈接到 DLL,應(yīng)用程序必須:

l  調(diào)用 LoadLibrary(或相似的函數(shù))以加載 DLL 和獲取模塊句柄。

l  調(diào)用 GetProcAddress,以獲取指向應(yīng)用程序要調(diào)用的每個導(dǎo)出函數(shù)的函數(shù)指針。由于應(yīng)用程序是通過指針調(diào)用 DLL 的函數(shù),編譯器不生成外部引用,故無需與導(dǎo)入庫鏈接。

l  使用完 DLL 后調(diào)用 FreeLibrary。

顯式調(diào)用C++動態(tài)庫注意點

C++來說,情況稍微復(fù)雜。顯式加載一個C++動態(tài)庫的困難一部分是因為C++name mangling;另一部分是因為沒有提供一個合適的API來裝載類,在C++中,您可能要用到庫中的一個類,而這需要創(chuàng)建該類的一個實例,這不容易做到。

name mangling可以通過extern 'C'解決。C++有個特定的關(guān)鍵字用來聲明采用C binding的函數(shù):extern 'C' 。用 extern 'C'聲明的函數(shù)將使用函數(shù)名作符號名,就像C函數(shù)一樣。因此,只有非成員函數(shù)才能被聲明為extern 'C',并且不能被重載。盡管限制多多,extern 'C'函數(shù)還是非常有用,因為它們可以象C函數(shù)一樣被dlopen動態(tài)加載。冠以extern 'C'限定符后,并不意味著函數(shù)中無法使用C++代碼了,相反,它仍然是一個完全的C++函數(shù),可以使用任何C++特性和各種類型的參數(shù)。

另外如何從C++動態(tài)庫中獲取類,附上幾篇相關(guān)文章,但我并不建議這么做:

l  LoadLibrary調(diào)用DLL中的Class》:http://www./codejie/archive/2009/09/24/97141.html

l  C++ dlopen mini HOWTO》:http://blog.csdn.net/denny_233/article/details/7255673

“顯式”使用C++動態(tài)庫中的Class是非常繁瑣和危險的事情,因此能用“隱式”就不要用“顯式”,能靜態(tài)就不要用動態(tài)。

附件:Linux下庫相關(guān)命令

g++(gcc)編譯選項

l  -shared :指定生成動態(tài)鏈接庫。

l  -static :指定生成靜態(tài)鏈接庫。

l  -fPIC :表示編譯為位置獨立的代碼,用于編譯共享庫。目標(biāo)文件需要創(chuàng)建成位置無關(guān)碼, 念上就是在可執(zhí)行程序裝載它們的時候,它們可以放在可執(zhí)行程序的內(nèi)存里的任何地方。

l  -L. :表示要連接的庫所在的目錄。

l  -l:指定鏈接時需要的動態(tài)庫。編譯器查找動態(tài)連接庫時有隱含的命名規(guī)則,即在給出的名字前面加上lib,后面加上.a/.so來確定庫的名稱。

l  -Wall :生成所有警告信息。

l  -ggdb :此選項將盡可能的生成gdb 的可以使用的調(diào)試信息。

l  -g :編譯器在編譯的時候產(chǎn)生調(diào)試信息。

l  -c :只激活預(yù)處理、編譯和匯編,也就是把程序做成目標(biāo)文件(.o文件。

l  -Wl,options :把參數(shù)(options)傳遞給鏈接器ld 。如果options 中間有逗號,就將options分成多個選項,然后傳遞給鏈接程序。

nm命令

有時候可能需要查看一個庫中到底有哪些函數(shù),nm命令可以打印出庫中的涉及到的所有符號。庫既可以是靜態(tài)的也可以是動態(tài)的。nm列出的符號有很多,常見的有三種:

l  一種是在庫中被調(diào)用,但并沒有在庫中定義(表明需要其他庫支持),用U表示;

l  一種是庫中定義的函數(shù),用T表示,這是最常見的;

l  一種是所謂的弱態(tài)”符號,它們雖然在庫中被定義,但是可能被其他庫中的同名符號覆蓋,用W表示。

$nm libhello.h

ldd命令

ldd命令可以查看一個可執(zhí)行程序依賴的共享庫,例如我們編寫的四則運算動態(tài)庫依賴下面這些庫:

總結(jié)

二者的不同點在于代碼被載入的時刻不同

l  靜態(tài)庫在程序編譯時會被連接到目標(biāo)代碼中,程序運行時將不再需要該靜態(tài)庫,因此體積較大。

l  動態(tài)庫在程序編譯時并不會被連接到目標(biāo)代碼中,而是在程序運行是才被載入,因此在程序運行時還需要動態(tài)庫存在,因此代碼體積較小。

動態(tài)庫的好處是,不同的應(yīng)用程序如果調(diào)用相同的庫,那么在內(nèi)存里只需要有一份該共享庫的實例。帶來好處的同時,也會有問題!如經(jīng)典的DLL Hell問題,關(guān)于如何規(guī)避動態(tài)庫管理問題,可以自行查找相關(guān)資料。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产成人午夜在线视频| 中国一区二区三区不卡| 欧美日不卡无在线一区| 五月婷婷六月丁香亚洲| 日韩欧美精品一区二区三区| 国产成人人人97超碰熟女| 中文日韩精品视频在线| 亚洲黄色在线观看免费高清| 微拍一区二区三区福利| 久久综合狠狠综合久久综合| 91播色在线免费播放| 人妻少妇久久中文字幕久久| 日本精品理论在线观看| 日本人妻精品中文字幕不卡乱码| 久久黄片免费播放大全 | 日本精品理论在线观看| 日木乱偷人妻中文字幕在线| 神马午夜福利一区二区| 亚洲国产欧美久久精品| 欧美成人免费夜夜黄啪啪| 国产亚洲欧美日韩精品一区| 日韩性生活视频免费在线观看 | 久久精品视频就在久久| 99久久精品免费看国产高清| 欧美午夜不卡在线观看| 国产一区日韩二区欧美| 视频一区日韩经典中文字幕| 国产成人免费高潮激情电| 91精品国产综合久久精品| 亚洲欧美国产网爆精品| 国产一区二区三区成人精品| 成人日韩在线播放视频| 好吊妞在线免费观看视频| 国产一区二区三区免费福利| 91人妻丝袜一区二区三区| 日韩三极片在线免费播放| 欧美一区日韩二区亚洲三区| 特黄大片性高水多欧美一级| 欧美日韩人妻中文一区二区| 久久成人国产欧美精品一区二区 | 大香蕉久草网一区二区三区|