青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Own Zone
Lotto
posts - 3,  comments - 3,  trackbacks - 0

ps:這篇文章是Unix下對(duì)于c++以及c的dll及類(lèi)的動(dòng)態(tài)加載以及原理的說(shuō)明,由此類(lèi)推到windows平臺(tái),也很實(shí)用

Trackback: http://blog.chinaunix.net/u1/46723/showart_570402.html

如何使用dlopen API動(dòng)態(tài)地加載C++函數(shù)和類(lèi)
C++ dlopen mini HOWTO 中譯版 [原創(chuàng)]
 
C++ dlopen mini HOWTO
作者:Aaron Isotton <aaron@isotton.com> 2006-03-16
譯者:Lolita@linuxsir.org 2006-08-05
------------------------------------------------
摘要
  如何使用dlopen API動(dòng)態(tài)地加載C++函數(shù)和類(lèi)

------------------------------------------------
目錄
  介紹
    版權(quán)和許可證
    不承諾
    貢獻(xiàn)者
    反饋
    術(shù)語(yǔ)
  問(wèn)題所在
    Name Mangling
    類(lèi)
  解決方案
    extern "C"
    加載函數(shù)
    加載類(lèi)
  源代碼 
  FAQ
  其他
  參考書(shū)

------------------------------------------------
介紹
  如何使用dlopen API動(dòng)態(tài)地加載C++函數(shù)和類(lèi),是Unix C++程序員經(jīng)常碰到的問(wèn)題。事實(shí)上,情況偶爾有些復(fù)雜,需要一些解釋。這正是寫(xiě)這篇mini HOWTO的緣由。
  理解這篇文檔的前提是對(duì)C/C++語(yǔ)言中dlopen API有基本的了解。這篇HOWTO的維護(hù)鏈接是 http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/

  版權(quán)和許可證
  這篇文檔《C++ dlopen mini HOWTO》版權(quán)為Aaron Isotton所有(copyrighted (c) 2002-2006),任何人在遵守自由軟件基金會(huì)制定的GPLv2許可證條款前提下可以自由拷貝、分發(fā)和修改這份文檔。

  不承諾
  本文不對(duì)文中的任何內(nèi)容作可靠性承諾。您必須為您自己使用文中任何概念、示例和信息承擔(dān)風(fēng)險(xiǎn),因?yàn)槠渲锌赡艽嬖阱e(cuò)誤和不準(zhǔn)確的地方,或許會(huì)損壞您的系統(tǒng)──盡管幾乎不可能發(fā)生此類(lèi)事故,但您還是小心行事──作者不會(huì)為此負(fù)任何責(zé)任。

  貢獻(xiàn)者
  在這篇文檔中,我欣然致謝(按字母順序):
  ◆ Joy Y Goodreau <joyg (at) us.ibm.com> 她的編輯工作.
  ◆ D. Stimitis <stimitis (at) idcomm.com> 指出一些formatting和name mangling的問(wèn)題, 還指出extern “C”的一些微妙之處。

  反饋
  歡迎對(duì)本文檔的反饋信息!請(qǐng)把您的補(bǔ)充、評(píng)論和批評(píng)發(fā)送到這個(gè)郵件地址:<aaron@isotton.com>。

  術(shù)語(yǔ)
  dlopen API
    關(guān)于dlclose、dlerror、dlopen和dlsym函數(shù)的描述可以在 dlopen(3) man手冊(cè)頁(yè)查到。
    請(qǐng)注意,我們使用“dlopen”時(shí),指的是dlopen函數(shù),而使用“dlopen API”則是指整個(gè)API集合。
------------------------------------------------
問(wèn)題所在
  有時(shí)你想在運(yùn)行時(shí)加載一個(gè)庫(kù)(并使用其中的函數(shù)),這在你為你的程序?qū)懸恍┎寮蚰K架構(gòu)的時(shí)候經(jīng)常發(fā)生。
  在C語(yǔ)言中,加載一個(gè)庫(kù)輕而易舉(調(diào)用dlopen、dlsym和dlclose就夠了),但對(duì)C++來(lái)說(shuō),情況稍微復(fù)雜。動(dòng)態(tài)加載一個(gè)C++庫(kù)的困難一部分是因?yàn)镃++的name mangling(譯者注:也有人把它翻譯為“名字毀壞”,我覺(jué)得還是不翻譯好),另一部分是因?yàn)閐lopen API是用C語(yǔ)言實(shí)現(xiàn)的,因而沒(méi)有提供一個(gè)合適的方式來(lái)裝載類(lèi)。
  在解釋如何裝載C++庫(kù)之前,最好再詳細(xì)了解一下name mangling。我推薦您了解一下它,即使您對(duì)它不感興趣。因?yàn)檫@有助于您理解問(wèn)題是如何產(chǎn)生的,如何才能解決它們。

  Name Mangling
  在每個(gè)C++程序(或庫(kù)、目標(biāo)文件)中,所有非靜態(tài)(non-static)函數(shù)在二進(jìn)制文件中都是以“符號(hào)(symbol)”形式出現(xiàn)的。這些符號(hào)都是唯一的字符串,從而把各個(gè)函數(shù)在程序、庫(kù)、目標(biāo)文件中區(qū)分開(kāi)來(lái)。
  在C中,符號(hào)名正是函數(shù)名:strcpy函數(shù)的符號(hào)名就是“strcpy”,等等。這可能是因?yàn)閮蓚€(gè)非靜態(tài)函數(shù)的名字一定各不相同的緣故。
  而C++允許重載(不同的函數(shù)有相同的名字但不同的參數(shù)),并且有很多C所沒(méi)有的特性──比如類(lèi)、成員函數(shù)、異常說(shuō)明──幾乎不可能直接用函數(shù)名作符號(hào)名。為了解決這個(gè)問(wèn)題,C++采用了所謂的name mangling。它把函數(shù)名和一些信息(如參數(shù)數(shù)量和大小)雜糅在一起,改造成奇形怪狀,只有編譯器才懂的符號(hào)名。例如,被mangle后的foo可能看起來(lái)像foo@4%6^,或者,符號(hào)名里頭甚至不包括“foo”。
  其中一個(gè)問(wèn)題是,C++標(biāo)準(zhǔn)(目前是[ISO14882])并沒(méi)有定義名字必須如何被mangle,所以每個(gè)編譯器都按自己的方式來(lái)進(jìn)行name mangling。有些編譯器甚至在不同版本間更換mangling算法(尤其是g++ 2.x和3.x)。即使您搞清楚了您的編譯器到底怎么進(jìn)行mangling的,從而可以用dlsym調(diào)用函數(shù)了,但可能僅僅限于您手頭的這個(gè)編譯器而已,而無(wú)法在下一版編譯器下工作。

  類(lèi)
  使用dlopen API的另一個(gè)問(wèn)題是,它只支持加載函數(shù)。但在C++中,您可能要用到庫(kù)中的一個(gè)類(lèi),而這需要?jiǎng)?chuàng)建該類(lèi)的一個(gè)實(shí)例,這不容易做到。

解決方案

  extern "C"
  C++有個(gè)特定的關(guān)鍵字用來(lái)聲明采用C binding的函數(shù):extern "C" 。 用 extern "C"聲明的函數(shù)將使用函數(shù)名作符號(hào)名,就像C函數(shù)一樣。因此,只有非成員函數(shù)才能被聲明為extern "C",并且不能被重載。盡管限制多多,extern "C"函數(shù)還是非常有用,因?yàn)樗鼈兛梢韵驝函數(shù)一樣被dlopen動(dòng)態(tài)加載。冠以extern "C"限定符后,并不意味著函數(shù)中無(wú)法使用C++代碼了,相反,它仍然是一個(gè)完全的C++函數(shù),可以使用任何C++特性和各種類(lèi)型的參數(shù)。

  加載函數(shù)
  在C++中,函數(shù)用dlsym加載,就像C中一樣。不過(guò),該函數(shù)要用extern "C"限定符聲明以防止其符號(hào)名被mangle。
  
  示例1.加載函數(shù)
代碼:

//----------
//main.cpp:
//----------
#include <iostream>
#include <dlfcn.h>

int main() {
    using std::cout;
    using std::cerr;

    cout << "C++ dlopen demo\n\n";

    // open the library
    cout << "Opening hello.so...\n";
    void* handle = dlopen("./hello.so", RTLD_LAZY);
   
    if (!handle) {
        cerr << "Cannot open library: " << dlerror() << '\n';
        return 1;
    }
   
    // load the symbol
    cout << "Loading symbol hello...\n";
    typedef void (*hello_t)();

    // reset errors
    dlerror();
    hello_t hello = (hello_t) dlsym(handle, "hello");
    const char *dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol 'hello': " << dlsym_error <<
            '\n';
        dlclose(handle);
        return 1;
    }
   
    // use it to do the calculation
    cout << "Calling hello...\n";
    hello();
   
    // close the library
    cout << "Closing library...\n";
    dlclose(handle);
}

//----------
// hello.cpp:
//----------
#include <iostream>

extern "C" void hello() {
    std::cout << "hello" << '\n';
}

  在hello.cpp中函數(shù)hello被定義為extern "C"。它在main.cpp中被dlsym調(diào)用。函數(shù)必須以extern "C"限定,否則我們無(wú)從知曉其符號(hào)名。
  警告:
  extern "C"的聲明形式有兩種:上面示例中使用的那種內(nèi)聯(lián)(inline)形式extern "C" , 還有才用花括號(hào)的extern "C" { ... }這種。 第一種內(nèi)聯(lián)形式聲明包含兩層意義:外部鏈接(extern linkage)和C語(yǔ)言鏈接(language linkage),而第二種僅影響語(yǔ)言鏈接。
  下面兩種聲明形式等價(jià):
代碼:

extern "C" int foo;
extern "C" void bar();


代碼:

extern "C" {
    extern int foo;
    extern void bar();
}

  對(duì)于函數(shù)來(lái)說(shuō),extern和non-extern的函數(shù)聲明沒(méi)有區(qū)別,但對(duì)于變量就有不同了。如果您聲明變量,請(qǐng)牢記:
代碼:

extern "C" int foo;

代碼:

extern "C" {
    int foo;
}

  是不同的物事(譯者注:簡(jiǎn)言之,前者是個(gè)聲明; 而后者不僅是聲明,也可以是定義)。
  進(jìn)一步的解釋請(qǐng)參考[ISO14882],7.5, 特別注意第7段; 或者參考[STR2000],9.2.4。在用extern的變量尋幽訪勝之前,請(qǐng)細(xì)讀“其他”一節(jié)中羅列的文檔。

  加載類(lèi)
  加載類(lèi)有點(diǎn)困難,因?yàn)槲覀冃枰?lèi)的一個(gè)實(shí)例,而不僅僅是一個(gè)函數(shù)指針。我們無(wú)法通過(guò)new來(lái)創(chuàng)建類(lèi)的實(shí)例,因?yàn)轭?lèi)不是在可執(zhí)行文件中定義的,況且(有時(shí)候)我們連它的名字都不知道。
  解決方案是:利用多態(tài)性! 我們?cè)诳蓤?zhí)行文件中定義一個(gè)帶虛成員函數(shù)的接口基類(lèi),而在模塊中定義派生實(shí)現(xiàn)類(lèi)。通常來(lái)說(shuō),接口類(lèi)是抽象的(如果一個(gè)類(lèi)含有虛函數(shù),那它就是抽象的)。
  因?yàn)閯?dòng)態(tài)加載類(lèi)往往用于實(shí)現(xiàn)插件,這意味著必須提供一個(gè)清晰定義的接口──我們將定義一個(gè)接口類(lèi)和派生實(shí)現(xiàn)類(lèi)。
  接下來(lái),在模塊中,我們會(huì)定義兩個(gè)附加的helper函數(shù),就是眾所周知的“類(lèi)工廠函數(shù)(class factory functions)(譯者注:或稱(chēng)對(duì)象工廠函數(shù))”。其中一個(gè)函數(shù)創(chuàng)建一個(gè)類(lèi)實(shí)例,并返回其指針; 另一個(gè)函數(shù)則用以銷(xiāo)毀該指針。這兩個(gè)函數(shù)都以extern "C"來(lái)限定修飾。
  為了使用模塊中的類(lèi),我們用dlsym像示例1中加載hello函數(shù)那樣加載這兩個(gè)函數(shù),然后我們就可以隨心所欲地創(chuàng)建和銷(xiāo)毀實(shí)例了。

  示例2.加載類(lèi)
  我們用一個(gè)一般性的多邊形類(lèi)作為接口,而繼承它的三角形類(lèi)(譯者注:正三角形類(lèi))作為實(shí)現(xiàn)。
代碼:

//----------
//main.cpp:
//----------
#include "polygon.hpp"
#include <iostream>
#include <dlfcn.h>

int main() {
    using std::cout;
    using std::cerr;

    // load the triangle library
    void* triangle = dlopen("./triangle.so", RTLD_LAZY);
    if (!triangle) {
        cerr << "Cannot load library: " << dlerror() << '\n';
        return 1;
    }

    // reset errors
    dlerror();
   
    // load the symbols
    create_t* create_triangle = (create_t*) dlsym(triangle, "create");
    const char* dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol create: " << dlsym_error << '\n';
        return 1;
    }
   
    destroy_t* destroy_triangle = (destroy_t*) dlsym(triangle, "destroy");
    dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
        return 1;
    }

    // create an instance of the class
    polygon* poly = create_triangle();

    // use the class
    poly->set_side_length(7);
        cout << "The area is: " << poly->area() << '\n';

    // destroy the class
    destroy_triangle(poly);

    // unload the triangle library
    dlclose(triangle);
}


//----------
//polygon.hpp:
//----------
#ifndef POLYGON_HPP
#define POLYGON_HPP

class polygon {
protected:
    double side_length_;

public:
    polygon()
        : side_length_(0) {}

    virtual ~polygon() {}

    void set_side_length(double side_length) {
        side_length_ = side_length;
    }

    virtual double area() const = 0;
};

// the types of the class factories
typedef polygon* create_t();
typedef void destroy_t(polygon*);

#endif

//----------
//triangle.cpp:
//----------
#include "polygon.hpp"
#include <cmath>

class triangle : public polygon {
public:
    virtual double area() const {
        return side_length_ * side_length_ * sqrt(3) / 2;
    }
};


// the class factories
extern "C" polygon* create() {
    return new triangle;
}

extern "C" void destroy(polygon* p) {
    delete p;
}

  加載類(lèi)時(shí)有一些值得注意的地方:
  ◆ 你必須(譯者注:在模塊或者說(shuō)共享庫(kù)中)同時(shí)提供一個(gè)創(chuàng)造函數(shù)和一個(gè)銷(xiāo)毀函數(shù),且不能在執(zhí)行文件內(nèi)部使用delete來(lái)銷(xiāo)毀實(shí)例,只能把實(shí)例指針傳遞給模塊的銷(xiāo)毀函數(shù)處理。這是因?yàn)镃++里頭,new操作符可以被重載;這容易導(dǎo)致new-delete的不匹配調(diào)用,造成莫名其妙的內(nèi)存泄漏和段錯(cuò)誤。這在用不同的標(biāo)準(zhǔn)庫(kù)鏈接模塊和可執(zhí)行文件時(shí)也一樣。
  ◆ 接口類(lèi)的析構(gòu)函數(shù)在任何情況下都必須是虛函數(shù)(virtual)。因?yàn)榧词钩鲥e(cuò)的可能極小,近乎杞人憂(yōu)天了,但仍舊不值得去冒險(xiǎn),反正額外的開(kāi)銷(xiāo)微不足道。如果基類(lèi)不需要析構(gòu)函數(shù),定義一個(gè)空的(但必須虛的)析構(gòu)函數(shù)吧,否則你遲早要遇到問(wèn)題,我向您保證。你可以在comp.lang.c++ FAQ( http://www.parashift.com/c++-faq-lite/ )的第20節(jié)了解到更多關(guān)于該問(wèn)題的信息。

源代碼
  你可以下載所有包含在本文檔中的代碼包: http://www.isotton.com/howtos/C++-dl...xamples.tar.gz

posted on 2008-06-06 23:52 Lotto 閱讀(3626) 評(píng)論(0)  編輯 收藏 引用

只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


Locations of visitors to this page

<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用鏈接

留言簿(1)

隨筆檔案

文章檔案

相冊(cè)

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            99国产精品99久久久久久| 亚洲免费在线看| 最新国产成人在线观看| 亚洲电影在线观看| 欧美精品日韩三级| 99热这里只有精品8| 国产资源精品在线观看| 老司机精品视频一区二区三区| 99re6热只有精品免费观看 | 午夜在线成人av| 国产欧美高清| 欧美午夜寂寞影院| 久久国产欧美精品| 韩国视频理论视频久久| 亚洲一级电影| 亚洲国产一区二区三区在线播| 狠狠色综合色区| 免费成人黄色片| 99re国产精品| 一区二区三区在线视频播放 | 久久综合狠狠综合久久综合88| 国产精品xxx在线观看www| 亚洲精品九九| 久久精品一区二区国产| 久久久久国产免费免费| 国产日韩欧美一二三区| 99精品热视频只有精品10| 久久久免费精品| 99精品热视频| 一级日韩一区在线观看| 午夜视频久久久| 欧美黄在线观看| 亚洲私人影院| 亚洲欧洲在线一区| 欧美国产91| 欧美精品日韩一本| 午夜精品在线观看| 欧美成人一品| 国产精品扒开腿做爽爽爽视频| 亚洲福利在线观看| 一本综合精品| 亚洲第一免费播放区| 亚洲激精日韩激精欧美精品| 久久综合色8888| 午夜精彩视频在线观看不卡| 女生裸体视频一区二区三区| 亚洲一区二区在线播放| 欧美第一黄色网| 久久超碰97中文字幕| 美国十次成人| 久久国产一区| 国产精品午夜在线观看| 日韩午夜激情| 99国内精品久久| 久久精品成人| 久久久九九九九| 国产欧美日韩精品丝袜高跟鞋| 最新国产乱人伦偷精品免费网站| 亚洲第一精品久久忘忧草社区| 欧美激情精品久久久久久久变态| 午夜精品福利一区二区蜜股av| 亚洲国产91| 美女网站在线免费欧美精品| 美女网站久久| 在线播放中文字幕一区| 久久精品官网| 久久亚洲一区二区| 黄网站色欧美视频| 久久免费高清视频| 欧美国产精品人人做人人爱| 亚洲国产一区二区精品专区| 牛牛影视久久网| 亚洲日本国产| 日韩一区二区免费看| 欧美日韩免费精品| 日韩视频二区| 午夜精品国产更新| 一区二区三区欧美在线| 亚洲第一色中文字幕| 久久免费国产精品| 麻豆91精品| 亚洲黄色精品| 欧美大片免费久久精品三p | 欧美福利一区| 最新热久久免费视频| 在线看片日韩| 欧美日韩高清在线一区| 一区二区三区福利| 久久精品中文| 亚洲精品综合久久中文字幕| 国产精品成人一区二区三区夜夜夜 | 精品动漫av| 久久噜噜亚洲综合| 99精品欧美一区二区蜜桃免费| 一级成人国产| 国产综合第一页| 欧美电影在线播放| 欧美一级片在线播放| 91久久久久久久久| 欧美怡红院视频一区二区三区| 亚洲第一搞黄网站| 欧美激情亚洲自拍| 欧美影院一区| 99精品视频网| 欧美3dxxxxhd| 午夜宅男欧美| 亚洲精品影视在线观看| 国产日韩欧美一区| 欧美日韩国产区一| 老司机精品福利视频| 一区二区三区四区五区精品视频| 久久久久看片| 亚洲一区二区在线观看视频| 伊人色综合久久天天| 国产精品劲爆视频| 蜜桃精品久久久久久久免费影院| 日韩亚洲不卡在线| 欧美www视频| 久久精品国产亚洲一区二区| 亚洲一本大道在线| 亚洲精品日韩一| 韩国精品主播一区二区在线观看| 欧美韩国日本一区| 久久精品色图| 日韩一级网站| 激情婷婷亚洲| 国产九色精品成人porny| 欧美日韩 国产精品| 久久久午夜视频| 欧美一区二区三区四区在线观看地址 | 欧美无乱码久久久免费午夜一区| 久久黄色小说| 午夜精品电影| 亚洲午夜免费福利视频| 免费在线成人av| 美女亚洲精品| 久久免费视频网| 久久福利毛片| 欧美一区二区免费| 亚洲欧美激情诱惑| 亚洲午夜精品一区二区| 亚洲一区网站| 亚洲欧美日韩在线| 亚洲欧美一区二区激情| 香蕉久久国产| 欧美一区二区三区日韩| 亚洲一区二区三区中文字幕在线| 亚洲开发第一视频在线播放| 亚洲国产精品一区在线观看不卡| 精品成人在线视频| 亚洲福利国产| 亚洲精品欧美专区| 一二三四社区欧美黄| 亚洲自拍偷拍麻豆| 午夜伦欧美伦电影理论片| 羞羞漫画18久久大片| 欧美亚洲综合久久| 久久久精品一区二区三区| 欧美成人免费在线| 亚洲国产综合在线看不卡| 亚洲国产精品久久精品怡红院| 亚洲福利一区| 99视频在线精品国自产拍免费观看| 久久夜色精品国产噜噜av| 最新高清无码专区| 99视频有精品| 亚洲综合国产| 久久久久九九九九| 欧美福利精品| 国产欧美日韩综合一区在线播放 | 免费久久99精品国产自在现线| 欧美成va人片在线观看| 国产精品高潮久久| 韩日精品在线| 99re6这里只有精品| 香蕉久久夜色精品国产| 狂野欧美激情性xxxx欧美| 亚洲精品国精品久久99热一| 亚洲一区二区三区四区视频| 久久精品一区二区国产| 免费不卡亚洲欧美| 国产美女高潮久久白浆| 亚洲精品黄网在线观看| 午夜精品一区二区三区在线视| 久久视频精品在线| 一本到12不卡视频在线dvd| 久久国产日本精品| 欧美性事免费在线观看| 激情欧美一区二区| 亚洲欧美国产精品va在线观看| 麻豆九一精品爱看视频在线观看免费| 亚洲精品在线观| 久久乐国产精品| 国产乱码精品| 一本色道久久综合亚洲精品小说 | 久久全国免费视频| 国产精品伦理| 欧美日韩国产免费观看| 久久免费视频在线观看| 亚洲一区二区久久|