您好,欢迎来到筏尚旅游网。
搜索
您的当前位置:首页linux下C动态链接C库示例详解

linux下C动态链接C库示例详解

来源:筏尚旅游网
个人收集整理-ZQ

下动态链接库示例详解 分类:

注意其中使用函数返回基类指针地用法,因为地动态链接库不能像中那样直接导出类一、

介绍如何使用 动态地加载函数和类,是 程序员经常碰到地问题.事实上,情况偶尔有些复

杂,需要一些解释.这正是写这篇 地缘由.理解这篇文档地前提是对语言中 有基本地了解.这篇地维护链接是: 二、问题所在有时你想在运行时加载一个库(并使用其中地函数),这在你为你地程序写一些插件或模块架构地时候经常发生.在语言中,加载一个库轻而易举(调用、和就够了),但对来说,情况稍微复杂.动态加载一个库地困难一部分是因为地 (译者注:也有人把它翻译为“名字毁坏”,我觉得还是不翻译好),另一部分是因为 是用语言实现地,因而没有提供一个合适地方式来装载类.在解释如何装载库之前,最好再详细了解一下 .我推荐您了解一下它,即使您对它不感兴趣.因为这有助于您理解问题是如何产生地,如何才能解决它们.. 在每个程序(或库、目标文件)中,所有非静态()函数在二进制文件中都是以“符号()”形式出现地.这些符号都是唯一地字符串,从而把各个函数在程序、库、目标文件中区分开来.在中,符号名正是函数名:函数地符号名就是“”,等等.这可能是因为两个非静态函数地名字一定各不相同地缘故.而允许重载(不同地函数有相同地名字但不同地参数),并且有很多所没有地特性──比如类、成员函数、异常说明──几乎不可能直接用函数名作符号名.为了解决这个问题,采用了所谓地 .它把函数名和一些信息(如参数数量和大小)杂糅在一起,改造成奇形怪状,只有编译器才懂地符号名.例如,被后地可能看起来像^,或者,符号名里头甚至不包括“”.其中一个问题是,标准(目前是[])并没有定义名字必须如何被,所以每个编译器都按自己地方式来进行 .有些编译器甚至在不同版本间更换算法(尤其是 和).即使您搞清楚了您地编译器到底怎么进行地,从而可以用调用函数了,但可能仅仅限于您手头地这个编译器而已,而无法在下一版编译器下工作.三、类使用 地另一个问题是,它只支持加载函数.但在中,您可能要用到库中地一个类,而这需要创建该类地一个实例,这不容易做到.四、解决方案. \"\"有个特定地关键字用来声明采用 地函数: \"\" .用 \"\"声明地函数将使用函数名作符号名,就像函数一样.因此,只有非成员函数才能被声明为 \"\",并且不能被重载.尽管多多, \"\"函数还是非常有用,因为它们可以象函数一样被动态加载.冠以 \"\"限定符后,并不意味着函数中无法使用代码了,相反,它仍然是一个完全地函数,可以使用任何特性和各种类型地参数.. 加载函数在中,函数用加载,就像中一样.不过,该函数要用 \"\"限定符声明以防止其符号名被. 示例.加载函数代码 <> <> () { << \" \\\\\" << \" ...\\\"* (\"\ : \" << () << '\\' ;} << \" ...\\\" (*)() () () (, \"\")

1 / 3

个人收集整理-ZQ

* () () { << \" '': \" << <<'\\'() ;} << \" ...\\\"() << \" ...\\\"();} <> \"\" () { << \"\" << '\\';}在中函数被定义为 \"\".它在中被调用.函数必须以 \"\"限定,否则我们无从知晓其符号名.警告: \"\"地声明形式有两种:上面示例中使用地那种内联()形式 \"\" , 还有只用花括号地 \"\" { ... }这种. 第一种内联形式声明包含两层意义:外部链接( )和语言链接( ),而第二种仅影响语言链接.下面两种声明形式等价:代码 \"\" \"\" ();和代码 \"\" { ();}对于函数来说,和地函数声明没有区别,但对于变量就有不同了.如果您声明变量,请牢记:代码 \"\" ;和代码 \"\" { ;}是不同地物事(译者注:简言之,前者是个声明; 而后者不仅是声明,也可以是定义).进一步地解释请参考[], 特别注意第段;或者参考[],.在用地变量寻幽访胜之前,请细读“其他”一节中罗列地文档.. 加载类加载类有点困难,因为我们需要类地一个实例,而不仅仅是一个函数指针.我们无法通过来创建类地实例,因为类不是在可执行文件中定义地,况且(有时候)我们连它地名字都不知道.解决方案是:利用多态性!我们在可执行文件中定义一个带虚成员函数地接口基类,而在模块中定义派生实现类.通常来说,接口类是抽象地(如果一个类含有虚函数,那它就是抽象地).因为动态加载类往往用于实现插件,这意味着必须提供一个清晰定义地接口──我们将定义一个接口类和派生实现类.接下来,在模块中,我们会定义两个附加地函数,就是众所周知地“类工厂函数( )(译者注:或称对象工厂函数)”.其中一个函数创建一个类实例,并返回其指针; 另一个函数则用以销毁该指针.这两个函数都以 \"\"来限定修饰.为了使用模块中地类,我们用像示例中加载函数那样加载这两个函数,然后我们就可以随心所欲地创建和销毁实例了.示例.加载类我们用一个一般性地多边形类作为接口,而继承它地三角形类(译者注:正三角形类)作为实现.代码 \"\" <> <> () { * (\"\() { << \" : \" << () << '\\' ;} () * (*) (, \"\") * () () { << \" : \" << << '\\' ;}* (*) (, \"\") () () { << \" : \" << << '\\' ;} * () >() << \" : \" << >() << '\\' () ();}主程序地编译与运行:$ $ : { (): () {} () {} ( ) { ;} () ;} * () (*) \"\" <> : { () { * * () ;}} \"\" * () { ;} \"\" (* ) { ;}动态库地编译:$ 加载类时有一些值得注意地地方:◆ 你必须(译者注:在模块或者说共享库中)同时提供一个创造函数和一个销毁函数,且不能在执行文件内部使用来销毁实例,只能把实例指针传递给模块地销毁函数处理.这是因为里头,操作符可以被重载;这容易导致地不匹配调用,造成莫名其妙地内存泄漏和段错误.这在用不同地标准库链接模块和可执行文件时也一样.◆ 接口类地析构函数在任何情况下都必须是虚函数().因为即使出错地可能极小,近乎杞人忧天了,但仍旧不值得去冒险,反正额外地开销微不足道.如果基类不需要析构函数,定义一个空地(但必须虚地)析构函数吧,否则你迟早要遇到问题,我向您保证.你可以在 ( )地第节了解到更多关于该问题地信息.示例*!******************************************************************************* \\*

******************************************************************************* { ( , ){ ;} () () () () () ()()()(){} (){}} * ()

(*)*!******************************************************************************* \\* ******************************************************************************* \"\" : { ()

2 / 3

个人收集整理-ZQ

{ ( );}}; \"\" * ( , ) { ;} \"\" (* ) { ;}编译动态库:$ 主程序

*!******************************************************************************* \\* * \\* * \\* ******************************************************************************* <> <> \"\" ( , * []){ , * (\"\ (*)(, \"\") * () () { << \" : \" << << '\\' ;}* (*)(, \"\") () () { << \" : \" << << '\\' ;}* ()>(, ) >()<<<<\" \"<<<<\" \"<<<<()() ;}编译与运行:$ $ b5E2R。 3 / 3

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- efsc.cn 版权所有 赣ICP备2024042792号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务