关于静态库和动态库

C/C++ 专栏收录该内容
30 篇文章 0 订阅

摘note
1.DLL
DLL好像是把我混淆了好长时间了---------因为一直把它当成动态链接的一个极好的例子来看...

事实上怎么样呢..

在拜读一本我非常推崇的计算机天文地理全典的时候,从个小细节联想到了好多

DLL是动态链接库吧?那它相当于UNIX中的SO(share object)吧?它是不是在程序运行的时候lorder挂接到内存中程序的?即是不是每个程序在lorder的时候,lorder做了次以前静态链接时编译器做的事情?

DLL在内存中只载入一次,然后在需要调用的时候进入的是这个DLL的领空而非一直在本程序的领空运行就可以使用DLL中的API,如此看来DLL它就不是严格意义的动态链接了?

可是在WINDOWS中,CPU是分段运行的,每个程序的地址空间是不同的,那这不同的地址空间中的同名DLL也就不可能是内存中同一个DLL了。以前,想法是这样简单的:windows的虚拟内存是映射到线性内存的,则线性内存中同一个DLL可以被同时映射到多个程序空间,也就是不同程序调用的是同一个DLL
默认的,一个共享库的TEXT节只有一个副本可以让其他程序调用.
简单的引申就是:也就是单核CPU上不同程序不可能同时调用同一个DLL

切换线程太明智了。

DLL:(win32+8086观念:)程序文件中保留着如何调用DLL中API,它包括那些东西,如何重定位,API的参数是什么;(8086观念造错)进入不同的领空是错误的说法,(win32观念)其实还是程序的领空,只不过这部分空间的东西不保存在硬盘上的程序文件中,而是在lorder的时候lorder联系到程序的(非链接),(win32观念:)这样程序就可以调用DLL中的API了

动态链接:
不像在命令行上传递OBJ文件那样,链接器并非必须把一个库中的所有OBJ文件都链接到最终的可执行文件中。事实上,正好相反。链接器不包含库中OBJ文件中的任何代码或数据,除非从那个OBJ文件中至少引用了一个符号。换句话说,链接器命令行中明确指定的OBJ文件总是被链接到最终的可执行文件中,而LIB文件中的OBJ文件只有在被引用过时才被链接进去。


明确DLL的设计:

导入表
Win32最基础的特性之一就是能够从其它可执行文件中导入函数。关于导入的DLL和函数的所有信息都存在于可执行文件中的一个称为导入表(Import Table)的表中。当它单独成节时,这个节的名字叫.idata。
导入对Win32可执行文件来说是至关重要的,因此,如果说链接器并不知道导入表方面的专业知识,那真是令人难以置信。但事实的确如此。换句话说,链接器并不知道,也不关心你调用的函数是在另外的DLL中,还是在这个文件中。链接器在这一点表现得特别聪明。它仅仅简单地依照上面描述的节组合规则和符号解析规则就创建了导入表,看起来好像它并没有意识到这个表的重要性。
让我们看一下一些导入库的片段,看一看链接器是怎样出色地完成这个任务的。图2是对USER32.LIB导入库运行DUMPBIN时的部分输出结果。假设你调用了ActivateKeyboardLayout这个API。在你的OBJ文件中可以找到一个_ActivateKeyboardLayout@8的修正记录。从USER32.LIB的头部,链接器知道这个函数可以在文件偏移0xEA14处的OBJ中找到。因此,链接器忠实地在最终的可执行文件中包含了上述指定的内容。
(于是程序调用ActivateKeyboardLayout时调用的是USER32.obj模块中的符号:连接器视角。)
牵涉到了OBJ文件中的许多节,包括.text,.idata$5,.idata$4和.idata$6。在.text节中是一个JMP指令(机器码0xFF 0x25)。从图3最后的COFF符号表可以看出,_ActivateKeyboardLayout@8被解析到了.text节的这个JMP指令上。因此,链接器把你对ActivateKeyboardLayout的调用转换成了对导入库的OBJ中的.text节的JMP指令的调用。
在可执行文件中,链接器把所有的.idata$XXX节组合成单个的.idata节。现在回忆一下链接器组合节名中带有$字符的节时要遵守的规则。如果从USER32.LIB导入的还有其它函数,它们的.idata$4,.idata$5和.idata$6这些节也要放入其中。结果就形成了所有的.idata$4节组成了一个数组,所有的.idata$5节组成了另一个数组。如果你熟悉“导入地址表(Import Address Table,IAT)”的话,这实际上就是它的创建过程。
最后,注意节.idata$6的原始数据中包含了字符串“ActivateKeyboardLayout”。这就是导入地址表中有被导入函数的名字的原因。重要的一点是,对链接器来说,创建导入表并非难事。它只是依照我前面描述的规则,做它自己的工作而已。

创建导出表
除了为可执行文件创建导入表外,链接器还负责创建导出表。它的工作难易参半。在第一遍中,链接器的任务是收集关于所有导出符号的信息并创建导出函数表。在此期间,链接器创建导出表,并且把它写入到OBJ文件中一个叫.edata的节中。这个OBJ文件除了扩展名是.EXP而不是.OBJ外,其它地方都符合标准。你使用DUMPBIN检查一下这些EXP文件的内容就知道了。
在第二遍中,链接器的工作就很轻松了。它只是把EXP文件当作普通的OBJ文件来对待。这也意味着OBJ文件中的节.edata应该被包含到可执行文件中。如果你在可执行文件看到.edata节,它就是导出表。但是,近来很少能找到.edata节。看起来好像是如果可执行文件使用Win32控制台或GUI子系统,链接器就自动合并.edata节和.rdata节,如果其中一个存在的话。

  很明显链接器做的工作要比我这里描述的多得多。例如,生成某种类型的调试信息(例如,CodeView信息)是链接器全部工作中的重要部分。但是,生成调试信息并不是必须的,因此我没有花什么时间来描述它。同样,链接器应该能够创建MAP文件,这种文件包含可执行文件中公共符号的列表,但是它同样不是必须的功能。
虽然我提供了许多复杂的背景知识,但是链接器的核心是简单地把多个编译单元组合成可执行文件。第一个基本功能是组合节;第二个功能是解析节之间的相互引用(修正)。联系一下诸如导出表之类系统特定的数据结构方面的知识,你就基本上掌握了这个功能强大且重要的工具。


2.动态链接
首先背一段经典:

存储器的一个有趣属性就是无聊一个系统有多大的存储器,它总是一种稀有的资源。磁盘空间和厨房的垃圾桶同样有这种属性。

动态链接的出现,对静态链接的代替原因在此.

按照以前种种对动态链接这种思想的丝丝扯淡,先想到的肯定是:动态链接在系统中只有一个,程序对函数的调用只使用它一个而已.

其实这2种思想也算程序员的惯性思维:当你碰到这个问题,有一段代码大部分程序都要用,如果很短的话分别放到每段代码中就可以了,如果长就单独放个函数或者宏迎或另外一个头文件里面

这种分开隔离大家一起调用的思想很简单也很有用

然后静态链接和动态链接的思想就明白了!

静态链接即把需要调用的库内容放到程序里面,动态链接即把内容隔离开来放到另外一个称为动态链接库的里面.

现在的include默认是动态链接。
想要设置静态链接方式调用一个函数可以在前面加上
inline


3.链接视角的编译符号修改
link啊,把各个obj链接成某种某种可执行文件
特殊的linux和win obj多为coff格式
coff又是极接近PE的。。

hmmmmmm
虽然link的作用看起来麻烦,但它做的事情实在是简单啊简单
把各个obj的节链接起来,把所有code段的地址调用组合起来,一般是根据程序员命名的名称来组合
编译器把code编译为obj时的命名方法是不确定的:

    例如c编译器是函数名称简单的加上"_"
        c++编译器还会在后面加上参数的说明,目的是为了重载。(重载函数是名字相同,但参数不同的函数。记住这些,你就会理解链接器是怎样处理重载的C++函数的。)

我们的两个事实说明公共符号与外部符号的名字在链接阶段必须匹配,还有就是,编译器改变了符号名。当你遇到“未解析的外部符号”这样的链接器消息时,要立即采取的行动再明显不过了:找出OBJ或LIB文件中的公共符号名,然后与链接器不能接受的符号名比较。它们几乎总是不相同的,解决这个问题的方法就是让这些符号名匹配。

暂时啊,link是只认名称的
不同的命名规则导致link时 c和c++编译器搞出来的玩意不能共存
extern "C"就是为此而存的,声明函数的命名使用C的规格

至于link对名称所引用对象的定址,完全是名称。
link前设置了对应关系的东西link会直接去查找,根据名称得到了就继续,得不到一个error。。
而没设置对应关系的,link会根据
"link.exe ??? ??? ??? para"
???的顺序决定了如何搜索"名称"
比如在第一个???发现了一个名称找不到对象,就在第二个???搜索下,没找到则第三个,循环。

头文件啊,存在的意义就在于声明未知的东西,至于link时 名称指向 对象的查找,完全是依据于名称。


PS:不同linker处理的顺序是不确定,60%的是按照std_call这种格式,剩下的是反着来,最好先了解下自己用的linker的属性,看看帮助最好:-)


4.调用库中的符号。
库中的符号可以以三种方式被引用。
首先,直接访问明确指定的OBJ文件中的符号。例如,如果在我的一个源文件中调用C++的printf函数,在我的OBJ文件中将会产生一个引用(和修正)。当创建可执行文件时,链接器会搜索它的LIB文件以查找包含printf代码的OBJ文件,并且链接相应的OBJ文件。
第二,可能存在一个间接引用。“间接”意味着通过第一种方法包含的OBJ引用了库中另外一个OBJ文件中的符号。而这第二个OBJ可能又引用了库中第三个OBJ文件中的符号。链接器的艰苦工作之一就是,即使符号通过49级间接引用,它也必须跟踪并且包含引用的每一个OBJ文件。
在三的位置,我们把目光转向导入库。在结构上,导入库与普通库并无区别。在解析符号(resolve symbol)时,链接器并不知道导入库与普通库的区别。它们的关键区别在于,导入库中的OBJ并没有相应的编译单元(例如,并没有相应的源文件)。实际上,是链接器自己基于正在创建的可执行文件所导出的符号产生导入库的。换句话说,链接器在创建可执行文件的导出表的同时也创建了相应的导入库来引用这些符号。

当查找符号时,链接器按它的命令行上遇到的LIB文件的顺序进行搜索。然而,一旦在某个库中找到一个符号,那个库就变成了首选库,首先在它里面搜索所有其它符号。一旦某个符号在这个库中找不到,这个库就失去了它的首选地位。此时,链接器搜索它的列表中的下一个库。


目的码链接库是带.LIB扩展名的文件。在使用连结程序进行静态连结时,它的程序代码就会加到程序的.EXE文件中。例如,在Microsoft Visual C++中,连同程序连结的一般C执行目的码链接库被称为LIBC.LIB。

引用链接库是目的码链接库文件的一种特殊形式。像目的码链接库一样,引用链接库有.LIB扩展名,并且被连结器用来确定程序代码中的函数呼叫来源。但引用链接库不含程序代码,而是为连结程序提供信息,以便在.EXE文件中建立动态链接时要用到的复位位表。包含在Microsoft编译器中的KERNEL32.LIB、USER32.LIB和GDI32.LIB文件是Windows函数的引用链接库。如果一个程序呼叫Rectangle函数,Rectangle将告诉LINK,该函数在GDI32.DLL动态链接库中。该信息被记录在.EXE文件中,使得程序执行时,Windows能够和GDI32.DLL动态链接库进行动态连结。

目的码链接库和引用链接库只用在程序开发期间使用,而动态链接库在执行期间使用。当一个使用动态链接库的程序执行时,该动态链接库必须在磁盘上。当Windows要执行一个使用了动态链接库的程序而需要加载该链接库时,动态链接库文件必须储存在含有该.EXE程序的目录下、目前的目录下、Windows系统目录下、Windows目录下,或者是在通过MS-DOS环境中的PATH可以存取到的目录下(Windows会按顺序搜索这些目录)。


链接FAQ:

不知出于什么原因,我不能在Microsoft和Borland的32位编译器之间混合使用OBJ文件和LIB文件。然而,在16位编译器上可以正常工作。这到底是为什么呢?


让我们先把目光对准OBJ文件,然后再说LIB文件。从PC出现到第一个Microsoft Win32编程工具出现,几乎所有编译器生成的OBJ文件都是Intel OMF格式。与OMF格式的OBJ文件打交道并不是一件轻松的事,因此,我并没有打算详细描述它。最初的Windows NT开发小组使用的OBJ文件格式被称为通用目标文件格式(Common Object File Format,COFF),而COFF格式是UNIX System V的正式机器代码格式。使用COFF相对容易。COFF格式的OBJ与可移植可执行(Portable Executable,PE)文件的格式非常接近,而可移植可执行文件格式又是Win32的可执行文件格式。COFF格式的链接器从COFF格式的文件创建EXE或DLL需要做的工作比从Intel OMF格式的文件要少。
就像有OMF和COFF格式的OBJ文件一样,LIB文件也有OMF格式与COFF格式之分。幸运的是,这两种格式的LIB文件都是仅仅把相应格式的一些OBJ文件放在一起组成的单个文件。专用记录中的附加信息可以让链接器快速从LIB文件中找到所需的OBJ文件。
混合使用不同编译器厂商的OBJ文件和LIB文件的问题是,并非每个厂商都把它的32位编译器转换到了COFF格式。Borland和Symantec仍旧使用OMF格式的OBJ文件和LIB文件,但是Microsoft的32位编译器生成COFF格式的OBJ文件和LIB文件。MASM 6.11默认情况下生成OMF格式的文件令人感到困惑,但使用/coff开关可以生成COFF格式的OBJ文件。
当链接不同格式的文件时,每个人可以猜猜链接器会做什么。例如,如果需要,Visual C++ 链接器可以把OMF格式的OBJ文件转换成COFF格式,但它遇到OMF格式的LIB文件时就拒绝工作。Borland的TLINK始终拒绝使用COFF格式的OBJ文件和LIB文件,Symantec C++ 7.2也是如此。Watcom 10.5好像选择的是COFF。结果混合不同编译器生成的文件经常造成混乱。链接器产生的模糊的错误信息并帮不了什么忙。
即使你不混合使用不同编译器生成的OBJ文件,你仍然会在混合使用由不同编译器生成的EXE和DLL时遇到问题。问题来自不同的导入库,这些导入库是一些非常小的OBJ文件的集合,能够告诉链接器某个特定的函数在正在链接的EXE或DLL之外的哪个DLL中。如果你提供了一个DLL,但不知道使用这个DLL的用户使用的是哪个编译器,这样,不同的LIB文件格式就会导致问题。大多数情况下你都得提供两种不同格式的导入库,一种是COFF格式,另一种是OMF格式。问题是,你怎样才能创建这些导入库呢?
如果你曾为Windows 3.x编过程序,你可能使用过编译器附带的一个叫做IMPLIB的工具。IMPLIB接受一个DLL作为输入,生成一个OMF格式的导入库。IMPLIB是通过读取它处理的DLL的导出节来达到上述效果的。因此,如果你使用像Borland C++ 或Symantec C++ 之类的编译器,你可以在任何你想链接的DLL上运行IMPLIB,这样就能得到合适格式的LIB文件。
可惜!32位版的Visual C++ 并没有附带像IMPLIB之类的工具。这是为什么呢?一个很好的解释就是由于文章前面提到的__stdcall类型的函数的名字粉碎。DLL导出的函数名字并不包含任何有关此函数所带参数个数的信息,因此,假定有这样一个IMPLIB,它也不知道怎样生成合适的__stdcall类型的名字(例如,_MessageBeep@4)。
幸运的是,在有些情况下,你可以使用一些鲜为人知技巧。不过这有些乱,并且仅适用于_cdecl类型的函数,不适用于__stdcall类型的函数。如果你想链接到某个DLL上,就创建一个相应的DEF文件。在这个DEF文件中,有一个EXPORTS节,所有需要包含在生成的LIB文件中的函数的名字都要在这个节中。不要在名字前加一个“_”字符,因为它会被自动加上。创建完DEF文件后,运行Microsoft的32位LIB工具,带上/MACHINE和/DEF选项。例如,要为MYDLL.DLL创建一个导入库,你可以先创建MYDLL.DEF文件,然后运行
LIB /MACHINE:i386 /DEF:MYDLL.DEF
如果一切顺利,这会创建一个名字叫MYDLL.LIB的COFF格式的导入库

 

 

 

 

 

我们可以创建一种文件里面包含了很多函数和变量的目标代码,链接的时候只要把这个文件指示给链接程序就自动地从文件中查找符合要求的函数和变量进行链接,整个查找过程根本不需要我们操心。
这个文件叫做 “库(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文件低很多。另外,由于是动态链接的,这给一些从事破坏工作的“高手”们多少带来了一些反汇编的困难。

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值