查看: 2513|回复: 0

Windows和Linux动态库差异分析

[复制链接]
发表于 2015-9-23 11:44:06 | 显示全部楼层 |阅读模式

动态链接库技术实现和设计程序常用的技术,在Windows和Linux系统中都有动态库的概念,采用动态库可以有效的减少程序大小,

节省空间,提 高效率,增加程序的可扩展性,便于模块化管理。但不同操作系统的动态库由于格式 不同,在需要不同操作系统调

用时需要进行动态库程序移植。本文分析和比较了两种操作系统动态库技术,并给出了将Visual C 编制的动态库移植到Linux上的

方法和经验。
  1、引言
  动态库(Dynamic Link Library abbr,DLL)技术是程序设计中经常采用的技术。其目的减少程序的大小,节省空间,提高效

率,具有很高的灵活性。采用动态库技术对于升级软件版本更加 容易。与静态库(Static Link Library)不同,动态库里面的函

数不是执行程序本身的一部分,而是根据执行需要按需载入,其执行代码可以同时在多个程序中共享。
  在Windows和Linux操作系统中,都可采用这种方式进行软件设计,但他们的调用方式以及程序编制方式不尽相同。本文首先分

析了在这两种 操作系统中通常采用的动态库调用方法以及程序编制方式,然后分析比较了这两种方式的不同之处,最后根据实际移

植程序经验,介绍了将VC 编制的Windows动态库移植到Linux下的方法。
  2、动态库技术
  2.1 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属性的模块语句组成的文本文件。
  2.2 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/ld.so.conf来让动态链接库为系统所使用,通常将动 态链接库所在目录名追加到动态链接库配置文件中。如具有X window

窗口系统发行版该文件中都具有/usr/X11R6/lib,它指向X window窗口系统的动态链接库所在目录。为了使动态链接库能为系统所

共享,还需运行动态链接库的管理命令./sbin/ldconfig。在编译所引 用的动态库时,可以在gcc采用 ?l或-L选项或直接引用所需

的动态链接库方式进行编译。在Linux里面,可以采用ldd命令来检查程序依赖共享库。
  3、两种系统动态库比较分析
  Windows和Linux采用动态链接库技术目的是基本一致的,但由于操作系统的不同,他们在许多方面还是不尽相同,下面从以下

几个方面进行阐述。
  (1)动态库程序编写,在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数作为初始化的人口,通常在导出

函数 的声明时需要有_declspec(dllexport)关键字。Linux下的gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要

到函 数做特别声明,编写比较方便。
  (2)动态库编译,在windows系统下面,有方便的调试编译环境,通常不用自己去编写makefile文件,但在linux下面,需要自己

动手去编写makefile文件,因此,必须掌握一定的makefile编写技巧,另外,通常Linux编译规则相对严格。
  (3)动态库调用方面,Windows和Linux对其下编制的动态库都可以采用显式调用或隐式调用,但具体的调用方式也不尽相同。
  (4)动态库输出函数查看,在Windows中,有许多工具和软件可以进行查看DLL中所输出的函数,例如命令行方式的dumpbin以及

VC 工具中的DEPENDS程序。在Linux系统中通常采用nm来查看输出函数,也可以使用ldd查看程序隐式链接的共享对象文件。
  (5)对操作系统的依赖,这两种动态库运行依赖于各自的操作系统,不能跨平台使用。因此,对于实现相同功能的动态库,必须

为两种不同的操作系统提供不同的动态库版本。
  4、动态库移植方法
  如果要编制在两个系统中都能使用的动态链接库,通常会先选择在Windows的VC 提供的调试环境中完成初始的开发,毕竟VC 提

供的图形化编辑和调试界面比vi

更多C语言 C++、JAVA、数电模电、51单片机PIC stm32 ARM Linux驱动 嵌入式、安卓系统 FPGADSP Cortex-M3学习


请咨询刘工:腾讯QQ3311615775 中国移动18365409359 深圳南山、民治、龙岗、西乡、长沙、郑州、南宁、广州同步学习中! 

理论与实践相结合 一线工程师项目经理教学 结合真实的产品案列 让你感受前所未有的电子产品的开发流程

2015给自己一个决心,只为自己!高薪就业不是梦,有想法你就来 IT达人等着你!!!


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
快速回复 返回顶部 返回列表