admin管理员组

文章数量:1538198

2024年3月27日发(作者:)

全面分析Linux动态库和windows动态库

本文这里分析Linux动态库和windows动态库通常采用的动态库调用方法以及

程序编制方式。动态库的目的减少程序的大小,节省空间,提高效率,具有很高的

灵活性。采用动态库技术对于升级软件版本更加容易,动态库里面的函数不是执行

程序本身的一部分,而是根据执行需要按需载入,其执行代码可以同时在多个程序

中共享。

windows动态库技术

动态链接库是实现Windows应用程序共享资源、节省内存空间、提高使用效率

的一个重要技术手段。常见的动态库包含外部函数和资源,也有一些动态库只包含

资源,如Windows字体资源文件,称之为资源动态链接库。通常动态库以.dll,.drv、.fon

等作为后缀。相应的windows静态库通常以.lib结尾,Windows自己就将一些主要

的系统功能以动态库模块的形式实现。

Windows动态库在运行时被系统加载到进程的虚拟空间中,使用从调用进程的

虚拟地址空间分配的内存,成为调用进程的一部分。DLL也只能被该进程的线程所

访问。DLL的句柄可以被调用进程使用;调用进程的句柄可以被DLL使用。DLL

模块中包含各种导出函数,用于向外界提供服务。DLL可以有自己的数据段,但没

有自己的堆栈,使用与调用它的应用程序相同的堆栈模式;一个DLL在内存中只有

一个实例;DLL实现了代码封装性;DLL的编制与具体的编程语言及编译器无关,

可以通过DLL来实现混合语言编程。DLL函数中的代码所创建的任何对象(包括

变量)都归调用它的线程或进程所有。

根据调用方式的不同,对动态库的调用可分为静态调用方式和动态调用方式。

(1)静态调用,也称为隐式调用,由编译系统完成对DLL的加载和应用程序结

束时DLL卸载的编码(Windows系统负责对DLL调用次数的计数),调用方式简

单,能够满足通常的要求。通常采用的调用方式是把产生动态连接库时产生的.LIB

文件加入到应用程序的工程中,想使用DLL中的函数时,只须在源文件中声明一下。

LIB文件包含了每一个DLL导出函数的符号名和可选择的标识号以及DLL文件名,

不含有实际的代码。Lib文件包含的信息进入到生成的应用程序中,被调用的DLL

文件会在应用程序加载时同时加载在到内存中。

(2)动态调用,即显式调用方式,是由编程者用API函数加载和卸载DLL来达

到调用DLL的目的,比较复杂,但能更加有效地使用内存,是编制大型应用程序时

的重要方式。在Windows系统中,与动态库调用有关的函数包括:

①LoadLibrary(或MFC 的AfxLoadLibrary),装载动态库。

②GetProcAddress,获取要引入的函数,将符号名或标识号转换为DLL内部地址。

③FreeLibrary(或MFC的AfxFreeLibrary),释放动态链接库。

在windows中创建动态库也非常方便和简单。在Visual C++中,可以创建不用

MFC而直接用C语言写的DLL程序,也可以创建基于MFC类库的DLL程序。每

一个DLL必须有一个入口点,在VC++中,DllMain是一个缺省的入口函数。DllMain

负责初始化(Initialization)和结束(Termination)工作。动态库输出函数也有两种约定,

分别是基于调用约定和名字修饰约定。DLL程序定义的函数分为内部函数和导出函

数,动态库导出的函数供其它程序模块调用。通常可以有下面几种方法导出函数:

①采用模块定义文件的EXPORT部分指定要输入的函数或者变量。

②使用MFC提供的修饰符号_declspec(dllexport)。

③以命令行方式,采用/EXPORT命令行输出有关函数。

在windows动态库中,有时需要编写模块定义文件(.DEF),它是用于描述DLL

属性的模块语句组成的文本文件。

Linux共享对象技术

在Linux操作系统中,采用了很多共享对象技术(Shared Object),虽然它和

Windows里的动态库相对应,但它并不称为动态库。相应的共享对象文件以.so作为

后缀,为了方便,在本文中,对该概念不进行专门区分。Linux系统的/lib以及标准

图形界面的/usr/X11R6/lib等目录里面,就有许多以so结尾的共享对象。同样,在

Linux下,也有静态函数库这种调用方式,相应的后缀以.a结束。Linux采用该共享

对象技术以方便程序间共享,节省程序占有空间,增加程序的可扩展性和灵活性。

Linux还可以通过LD-PRELOAD变量让开发人员可以使用自己的程序库中的模块来

替换系统模块。

同Windows系统一样,在Linux中创建和使用动态库是比较容易的事情,在编

译函数库源程序时加上-shared选项即可,这样所生成的执行程序就是动态链接库。

通常这样的程序以so为后缀,在Linux动态库程序设计过程中,通常流程是编写用

户的接口文件,通常是.h文件,编写实际的函数文件,以.c或.cpp为后缀,再编写

makefile文件。对于较小的动态库程序可以不用如此,但这样设计使程序更加合理。

编译生成动态连接库后,进而可以在程序中进行调用。在Linux中,可以采用

多种调用方式,同Windows的系统目录(..system32等)一样,可以将动态库文件拷

贝到/lib目录或者在/lib目录里面建立符号连接,以便所有用户使用。下面介绍Linux

调用动态库经常使用的函数,但在使用动态库时,源程序必须包含dlfcn.h头文件,

该文件定义调用动态链接库的函数的原型。

(1)_打开动态链接库:dlopen,函数原型void *dlopen (const char *filename, int

flag);

dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。

(2)取函数执行地址:dlsym,函数原型为: void *dlsym(void *handle, char *symbol);

dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执

行代码地址。

(3)关闭动态链接库:dlclose,函数原型为: int dlclose (void *handle);

dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,

才会真正被系统卸载。

(4)动态库错误函数:dlerror,函数原型为: const char *dlerror(void); 当动态链接

库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函

数执行成功。

在取到函数执行地址后,就可以在动态库的使用程序里面根据动态库提供的函

数接口声明调用动态库里面的函数。在编写调用动态库的程序的makefile文件时,

需要加入编译选项-rdynamic和-ldl。

除了采用这种方式编写和调用动态库之外,Linux操作系统也提供了一种更为

方便的动态库调用方式,也方便了其它程序调用,这种方式与Windows系统的隐式

链接类似。其动态库命名方式为“lib*.so.*”。在这个命名方式中,第一个*表示动态

链接库的库名,第二个*通常表示该动态库的版本号,也可以没有版本号。在这种调

用方式中,需要维护动态链接库的配置文件/etc/来让动态链接库为系统所

使用,通常将动态链接库所在目录名追加到动态链接库配置文件中。如具有X

window窗口系统发行版该文件中都具有/usr/X11R6/lib,它指向X window窗口系统

的动态链接库所在目录。为了使动态链接库能为系统所共享,还需运行动态链接库

的管理命令./sbin/ldconfig。在编译所引用的动态库时,可以在gcc采用 –l或-L选项

或直接引用所需的动态链接库方式进行编译。在Linux里面,可以采用ldd命令来

检查程序依赖共享

本文标签: 动态调用函数方式