静态链接库和动态链接库(转)

我们可以创建一种文件里面包含了很多函数和变量的目标代码,链接的时候只要把这个文件指示给链接程序就自动地从文件中查找符合要求的函数和变量进行链接,整个查找过程根本不需要我们操心。
这个文件叫做 “库(Libary)”,平时我们把编译好的目标代码存储到“库”里面,要用的时候链接程序帮我们从库里面找出来。

静态链接库:

  在早期库的组织形式相对简单,里面的目标代码只能够进行静态链接,所以我们称为“静态库”,静态库的结构比较简单,其实就是把原来的目标代码放在一起,链接程序根据每一份目标代码的符号表查找相应的符号(函数和变量的名字),找到的话就把该函数里面需要定位的进行定位,然后将整块函数代码放进可执行文件里,若是找不到需要的函数就报错退出。
静态库的两个特点:

#1链接后产生的可执行文件包含了所有需要调用的函数的代码,因此占用磁盘空间较大。

#2如果有多个(调用相同库函数的)进程在内存中同时运行,内存中就存有多份相同的库函数代码,因此占用内存空间较多。


动态链接库:

动态链接库就是为了解决这些问题而诞生的技术,顾名思义,动态链接的意思就是在程序装载内存的时候才真正的把库函数代码链接进行确定它们的地址,并且就算有几个程序同时运行,内存也只存在一份函数代码。

  动态库的代码必须满足这样一种条件:能够被加载到不同进程的不同地址,所以代码要经过特别的编译处理,我们把这种经过特别处理的代码叫做“位置无关代码(Position independed Code .PIC)”.

  根据载入程序何时确定动态代码的逻辑地址,可以把动态装载分为两类。

#1 静态绑定(static binding)

使用静态绑定的程序一开始载入内存的时候,载入程序就会把程序所有调用到的动态代码的地址算出确定下来,这种方式使程序刚运行的初始化时间较长,不过旦完成动态装载,程序的运行速度就很快。

#2动态绑定(dynamic binding)

使用这种方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态绑定的程序。

平时默认进行链接的标准 C/C++ 函数就是动态库。

Note:
  内存中的动态代码只有一份副本,但动态库的数据仍然可能有多份副本,因为每一个链接到动态的进程都可能会修改库的数据,每当出现这种情况的时候,操作系统就复制出一份数据副本,然后修改进程的地址空间映射,使它指向新的数据副本,于是进程最后修改的只是属于自己的那份数据。


一、如何使用静态链接库?

1. .h和.lib放到你工程目录下面
2.在stdafx.h里面,加入
#include "xxx.h"
#pragma comment(lib,"xxx.lib")


二、动态链接库转换为静态链接库?

   > cd /c/usr/src/lib
   > pexports.exe ../bin/iconv.dll > iconv.def
   > dlltool.exe -e libiconv.exp -l libiconv.a -D iconv.dll -d iconv.def -z libiconv.def -k -v
   > ranlib libiconv.a

动态.dll -> 静态.lib:
使用DLL to Lib工具转换,此工具收费。

动态.dll _> 动态.lib:
使用VC的lib.exe工具,可以由.DLL生成.Lib


 三、C 静态链接库LIB的制作?

要创建静态库,选择File->New菜单,弹出New对话框。选择Projects标签,在项目类型列表框中选择Win32 Static Library,在Name中输入mymath,表明要创建一个mymath.lib的静态库文件。

然后用Project->Add to Project->Files菜单往mymath工程中加入以下两个文件:

//MyLib.h

#ifndef _MYMATH_H
#define _MYMATH_H
extern "C"
{
 int Summary(int n);
}
#endif

//MyLib.c

extern "C" int Summary(int n)
{
 return n+2;
}

//编译程序

//使用
#i nclude "MyLib.h"
LIB MyLib.lib

就可以使用导出的函数

四、如何在VC.NET中制作并使用动态链接库DLL?

1、将C++类做成DLL
  建立一个MFC DLL工程,PacketTransfer;将类的头文件搞到PacketTransfer.h中,并在要在外部调用的类声明前加_declspec(dllexport),如:要在外内调用CPacketTransfer类,可对该类做声明:
  class _declspec(dllexport) CPacketTransfer
  {
   ……
  };
  将类的定义文件内容拷到Sample.cpp中,然后生成该工程,生成的文件有:PacketTransfer.dll和PacketTransfer.lib
2、调用DLL中的C++类
  将PacketTransfet.h,PacketTransfer.dll和PacketTransfer.lib拷贝到要调用的工程目录下,在工程属性中加入输入:PacketTransfer.lib,并包含头文件PacketTransfer.h,就可以使用类CPacketTransfer了:
  CPacketTransfer temp,*pTest;……

3、将C或C++函数接口做成DLL
      建立一个MFC DLL工程,api;将用到的头文件声明拷贝加到api.h中,将其它代码拷到api.cpp中,并在所有要调用的接口函数声明前加入导出声明,如:
  extern "C" _declspec(dllexport) bool MakeMD5File(char *file,char *key);
    然后生成该工程,得到文件api.dll和api.lib
4、使用DLL中的接口
  将api.dll和api.lib拷到工程目录下,在工程属性中加入输入:api.lib,然后在使用接口函数前用extern "C" _declspec(dllimport)声明该接口即可:
  extern "C" _declspec(dllimport) bool MakeMD5File(char *file,char *key);
    然后可以使用该函数的,也可以用LoadLibrary()等系统API直接调用DLL中的接口.

 五、使用动态链接库DLL的方法?

我们可以把 .dll 文件想象成 .c 或 .cpp 文件,
函数的主体在这个文件中,而函数的定义在 .h 文件中,
我们把 .lib 文件想象成 .dll 中函数的声明,
因此,只要把 .h, .lib, .dll 三个文件安排好,
让你的程序能找到它们就可以像使用自己写的函数一样适用 .dll 中的函数了。
具体方法如下:
1、建立一个简单的C程序
2、添加想要使用的 .dll 中的函数(这是opencv库中的功能)
   此时会提示有错误,没有任何代码,就是用函数和结构体,当然会告诉你没定义了;-)
3、将 .h 文件拷贝过来
  至于你应该拷贝哪个 .h 文件,你自己必须知道,就是那个 .dll 文件对应的 .h 文件
  现在编译后错误少了两个,确切的说应该是错误都去掉了,多了一个新错误,说没有cxcore.h文件
  这是拷贝过来的highgui.h文件需要的,我们来看看,
  看到了吧,就是说这个文件必须引用另一个文件。
  真实情况是这样的:这个 .dll 文件需要另一个 .dll 文件的支持,我们如发泡制,也把头文件拷贝过来
  又出现一个新的错误,缺少cxtypes.h文件,这是刚拷贝来的cxcore.h文件需要的,我们继续拷贝
  
4、 注意啦!要看看错误的类型,已经不是编译错误啦,而是连接错误,说明语法已经没有错误,是缺少函数的实体了。
  现在的情况就相当于我们已经在 .h 文件中定义了调用的函数,但是没有给出函数实体。我们把函数实体 .dll 文件
  拷贝过来。应该拷贝的 .dll 文件,你自己应该知道,如果不知道,sorry,错啦
  刚才的错误是连接错误,这个时候它找的是函数的声明,因为 .dll 文件只有在运行时才会涉及到。为了证明这一点,
  我们把刚拷贝来的 .dll 文件都删除。然后把 .lib 文件拷贝来
  为什么还有错误? 因为你并没有告诉程序应该连接它,怎么样,没有任何错误了吧。我们运行看看
  这就是运行时错误了,因为没有可用的 .dll 文件,因此提示错误,按照它提示的 .dll 文件,我们把它拷贝过来。
  又提示了一个新的错误,缺少另一个 .dll文件,我说过了,前面的那个 .dll文件需要后面的这个支持.
  这回运行出来了.


 六、VC++中使用静态链接库和动态链接库小结?

最近在VC++使用GSL(GNU科学计算库)静态库和动态库时遇到了一些问题,做个小结,以备参考。
       静态库包括.lib和.h文件,在工程中使用静态库分为3步:
1在工程中加入静态库,有两种方法:
方法一:项目设置中引用.lib,project-setting-link-object/library modules中添加.lib;(需要在tools/options设置正确的引用路径)
方法二:在项目中直接加入lib,project-add to project-files,选择正确的.lib。
2在工程中包括.h文件;(可能 需要在tools/options设置正确的引用路径)
3在工程中使用静态库中的函数;--大功告成!
       动态链接库一般包括.lib(导出函数),.h,.dll,使用动态库有两种情况:
1隐式链接,同使用静态库相似,分为三步:引用.lib,包含头文件,使用导出函数;
2动态加载,直接使用LoadLibrary 加载所需的动态库,然后指定所需的导出函数,效率最高!
七、为什么要使用动态链接库(DLL)?
提起DLL您一定不会陌生,在Windows中有着大量的以DLL为后缀的文件,它们是保证Windows正常运行和维护升级的重要保证。(举个例子,笔者的Win95 System目录下尽有500多个DLL文件。)其实,DLL是一种特殊的可执行文件。说它特殊主要是因为一般它都不能直接运行,需要宿主程序比如*.EXE程序或其他DLL的动态调用才能够使用。简单的说,在通常情况下DLL是经过编译的函数和过程的集合。
使用DLL技术主要有以下几个原因:
1、减小可执行文件大小。
    DLL技术的产生有很大一部分原因是为了减小可执行文件的大小。当操作系统进入Windows时代后,其大小已经达到几十兆乃至几百兆。试想如果还是使用DOS时代的单执行文件体系的话一个可执行文件的大小可能将达到数十兆,这是大家都不能接受的。解决的方法就是采用动态链接技术将一个大的可执行文件分割成许多小的可执行程序。
2、实现资源共享。
    这里指的资源共享包括很多方面,最多的是内存共享、代码共享等等。早期的程序员经常碰到这样的事情,在不同的编程任务中编写同样的代码。这种方法显然浪费了很多时间,为了解决这个问题人们编写了各种各样的库。但由于编程语言和环境的不同这些库一般都不能通用,而且用户在运行程序时还需要这些库才行,极不方便。DLL的出现就像制定了一个标准一样,使这些库有了统一的规范。这样一来,用不同编程语言的程序员可以方便的使用用别的编程语言编写的DLL。另外,DLL还有一个突出的特点就是在内存中只装载一次,这一点可以节省有限的内存,而且可以同时为多个进程服务。
3、便于维护和升级。
    细心的朋友可能发现有一些DLL文件是有版本说明的。(查看DLL文件的属性可以看到,但不是每一个DLL文件都有)这是为了便于维护和升级。举个例子吧,早期的Win95中有一个BUG那就是在闰年不能正确显示2月29日这一天。后来,Microsoft发布了一个补丁程序纠正了这个BUG。值得一提的是,我们并没有重装Win95,而是用新版本的DLL代替了旧版本的DLL。(具体是哪一个DLL文件笔者一时想不起来了。)另一个常见的例子是驱动程序的升级。例如,著名的DirectX就多次升级,现在已经发展到了6.0版了。更妙的是,当我们试图安装较低版本的DLL时,系统会给我们提示,避免人为的操作错误。例如我们升级某硬件的驱动程序时,经常碰到Windows提示我们当前安装的驱动程序比原来的驱动程序旧。
4、比较安全。
    这里说的安全也包括很多方面。比如,DLL文件遭受病毒的侵害机率要比普通的EXE文件低很多。另外,由于是动态链接的,这给一些从事破坏工作的“高手”们多少带来了一些反汇编的困难。

posted @ 2010-06-15 10:05  andriod2012  阅读(196)  评论(0编辑  收藏  举报