1、链接库概念
静态链接库和动态链接库介绍
我们可以创建一种文件里面包含了很多函数和变量的目标代码,链接的时候只要把这个文件指示给链接程序就自动地从文件中查找符合要求的函数和变量进行链接,整个查找过程根本不需要我们操心。
这个文件叫做 “库(Libary)”,平时我们把编译好的目标代码存储到“库”里面,要用的时候链接程序帮我们从库里面找出来。
静态链接库:
在早期库的组织形式相对简单,里面的目标代码只能够进行静态链接,所以我们称为“静态库”,静态库的结构比较简单,其实就是把原来的目标代码放在一起,链接程序根据每一份目标代码的符号表查找相应的符号(函数和变量的名字),找到的话就把该函数里面需要定位的进行定位,然后将整块函数代码放进可执行文件里,若是找不到需要的函数就报错退出。
静态库的两个特点:
1、链接后产生的可执行文件包含了所有需要调用的函数的代码,因此占用磁盘空间较大。
2、如果有多个(调用相同库函数的)进程在内存中同时运行,内存中就存有多份相同的库函数代码,因此占用内存空间较多。
动态链接库:
动态链接库就是为了解决这些问题而诞生的技术,顾名思义,动态链接的意思就是在程序装载内存的时候才真正的把库函数代码链接进行确定它们的地址,并且就算有几个程序同时运行,内存也只存在一份函数代码。
动态库的代码必须满足这样一种条件:能够被加载到不同进程的不同地址,所以代码要经过特别的编译处理,我们把这种经过特别处理的代码叫做“位置无关代码(Position independed Code .PIC)”.
根据载入程序何时确定动态代码的逻辑地址,可以把动态装载分为两类。
1、静态绑定(static binding)
使用静态绑定的程序一开始载入内存的时候,载入程序就会把程序所有调用到的动态代码的地址算出确定下来,这种方式使程序刚运行的初始化时间较长,不过旦完成动态装载,程序的运行速度就很快。
2、动态绑定(dynamic binding)
使用这种方式的程序并不在一开始就完成动态链接,而是直到真正调用动态库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态绑定的程序。
平时默认进行链接的标准 C/C++ 函数就是动态库。
2、链接库常识
目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库”)。
静态库是一个或者多个obj文件的打包,所以有人干脆把从obj文件生成lib的过程称为Archive,即合并到一起。比如你链接一个静态库,如果其中有错,它会准确的找到是哪个obj有错,即静态lib只是壳子。
动态库一般会有对应的导入库,方便程序静态载入动态链接库,否则你可能就需要自己LoadLibary调入DLL文件,然后再手工GetProcAddress获得对应函数了。有了导入库,你只需要链接导入库后按照头文件函数接口的声明调用函数就可以了。
导入库和静态库的区别很大,他们实质是不一样的东西。静态库本身就包含了实际执行代码、符号表等等,而对于导入库而言,其实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。 这也是实际上很多开源代码发布的惯用方式:
1. 预编译的开发包:包含一些.dll文件和一些.lib文件。其中这里的.lib就是导入库,而不要错以为是静态库。但是引入方式和静态库一样,要在链接路径上添加找到这些.lib的路径。而.dll则最好放到最后产生的应用程序exe执行文件相同的目录。这样运行时,就会自动调入动态链接库。
2. 用户自己编译: 下载的是源代码,按照readme自己编译。生成很可能也是.dll + .lib(导入库)的库文件
3. 如果你只有dll,并且你知道dll中函数的函数原型,那么你可以直接在自己程序中使用LoadLibary调入DLL文件,GetProcAddress
DLL:
动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。
动态链接与静态链接的不同之处在于它允许可执行模块(.dll 文件或 .exe 文件)仅包含在运行时定位 DLL 函数的可执行代码所需的信息。在静态链接中,链接器从静态链接库获取所有被引用的函数,并将库同代码一起放到可执行文件中。
使用动态链接代替静态链接有若干优点。扩展了应用程序的特性、、可以用许多种编程语言来编写、简化了软件项目的管理、有助于节省内存、有助于资源共享、有助于应用程序的本地化、有助于解决平台差异、可以用于一些特殊的目的。windows使得某些特性只能为DLL所用。
3、动态链接库的调用
有两种类型的链接:隐式链接和显式链接。
隐式链接
应用程序的代码调用导出 DLL 函数时发生隐式链接。 当调用可执行文件的源代码被编译或被汇编时,DLL 函数调用在对象代码中生成一个外部函数引用。 若要解析此外部引用,应用程序必须与 DLL 的创建者所提供的导入库(.LIB 文件)链接。
导入库仅包含加载 DLL 的代码和实现 DLL 函数调用的代码。 在导入库中找到外部函数后,会通知链接器此函数的代码在 DLL 中。 要解析对 DLL 的外部引用,链接器只需向可执行文件中添加信息,通知系统在进程启动时应在何处查找 DLL 代码。
系统启动包含动态链接引用的程序时,它使用程序的可执行文件中的信息定位所需的 DLL。 如果系统无法定位 DLL,它将终止进程并显示一个对话框来报告错误。 否则,系统将 DLL 模块映射到进程的地址空间中。
如果任何 DLL 具有(用于初始化代码和终止代码的)入口点函数,操作系统将调用此函数。 在传递到入口点函数的参数中,有一个指定用以指示 DLL 正在附带到进程的代码。 如果入口点函数没有返回 TRUE,系统将终止进程并报告错误。
最后,系统修改进程的可执行代码以提供 DLL 函数的起始地址。
与程序代码的其余部分一样,DLL 代码在进程启动时映射到进程的地址空间中,且仅当需要时才加载到内存中。 因此,由 .def 文件用来在 Windows 的早期版本中控制加载的 PRELOAD 和 LOADONCALL 代码特性不再具有任何意义。
显式链接
大部分应用程序使用隐式链接,因为这是最易于使用的链接方法。 但是有时也需要显式链接。 下面是一些使用显式链接的常见原因:
直到运行时,应用程序才知道需要加载的 DLL 的名称。 例如,应用程序可能需要从配置文件获取 DLL 的名称和导出函数名。
如果在进程启动时未找到 DLL,操作系统将终止使用隐式链接的进程。 同样是在此情况下,使用显式链接的进程则不会被终止,并可以尝试从错误中恢复。 例如,进程可通知用户所发生的错误,并让用户指定 DLL 的其他路径。
如果使用隐式链接的进程所链接到的 DLL 中有任何 DLL 具有失败的 DllMain 函数,该进程也会被终止。 同样是在此情况下,使用显式链接的进程则不会被终止。
因为 Windows 在应用程序加载时加载所有的 DLL,故隐式链接到许多 DLL 的应用程序启动起来会比较慢。 为提高启动性能,应用程序可隐式链接到那些加载后立即需要的 DLL,并等到在需要时显式链接到其他 DLL。
显式链接下不需将应用程序与导入库链接。 如果 DLL 中的更改导致导出序号更改,使用显式链接的应用程序不需重新链接(假设它们是用函数名而不是序号值调用 GetProcAddress),而使用隐式链接的应用程序必须重新链接到新的导入库。
下面是需要注意的显式链接的两个缺点:
如果 DLL 具有 DllMain 入口点函数,则操作系统在调用 LoadLibrary 的线程上下文中调用此函数。 如果由于以前调用了 LoadLibrary 但没有相应地调用 FreeLibrary 函数而导致 DLL 已经附加到进程,则不会调用此入口点函数。 如果 DLL 使用 DllMain 函数为进程的每个线程执行初始化,显式链接会造成问题,因为调用 LoadLibrary(或 AfxLoadLibrary)时存在的线程将不会初始化。
如果 DLL 将静态作用域数据声明为 __declspec(thread),则在显式链接时 DLL 会导致保护错误。 用 LoadLibrary 加载 DLL 后,每当代码引用此数据时 DLL 就会导致保护错误。 (静态作用域数据既包括全局静态项,也包括局部静态项。)因此,创建 DLL 时应避免使用线程本地存储区,或者应(在用户尝试动态加载时)告诉 DLL 用户潜在的缺陷。
4、显示链接和隐式链接的区别
一、Implicit Linking(隐式连接)
Implicit Linking(隐式连接) ,又叫静态载入,所谓静态载入是指程序在连接时期即与dlls所对应的import libraries作静态连接,于是可执行文件中便对所有的dll函数都有一份重定位表格(relocation table)和待修正记录(fixup record)。当程序被windows载入器载入内存中时,载入器会自动修正所有的fixup records,而这个fixup records 就是记录DLL中所有输出资源的正确位置地址,经过这样的程序动态连接便自动产生。也就是说,程序开始执行时,会用静态载入的方式时所使用的DLLs都载入到程序的内存里。
静态载入方式的优点
1、静态载入方式所使用的dll会在应用程序执行时载入,然后就可以调用所有dll中提供的函数,就像是程序中一样。
2、处理简单,载入的方法有编译器负责处理,不需动脑筋。
静态载入方式的缺点
1、当程序机构态载入方式所使用的dll不存在时,程序开始就会报dll无法找到的错误而使得程序无法运行。
编译时需要加入import library。
2、若调用的dll很多,载入应用程序的速度就会很慢。
不同的c++编译器静态载入的方式也不一样。
二、Explicit Linking(显式连接)
所谓Explicit Link(显式连接)又叫动态载入,使用dll的可执行文件必须明确调用载入和御载dll的函数调用(Function Call),并且存取dll的输出函数。用户端必须通过函数声明调用函数。
可执行文件可以使用任何一种连接方式的相同低dll。并且,这些机制之间并不会相互排斥,因此,当一个可执行文件隐式的连接dll时,其他程序还可以显示地连接它。
动态载入方式的优缺点:
1、dll只有需要时才载入内存中,这样可以更有效地使用存储空间。
2、应用程序载入速度较隐式连接较快,因为当程序开始载入时并不需要把dll载入到程序中。
3、编译时不需要额外的import library。
4、可以让用户个清楚地知道dll的载入流程。
缺点就是必须多写一点代码。
动态载入基本流程
必须使用LoadLibrary这个Windows API来手动载入DLL,并使用GetProcessAddress来取得所需要使用的函数的函数指针,最后用FreeLibrary将DLL释放。所以学会动态载入DLL时,必须先知道函数指针的用法。
- 动态链接库dll,静态链接库lib, 导入库lib
转载地址:http://www.cnblogs.com/chio/archive/2008/08/05/1261296.html 目前以lib后缀的库有两种,一种为静态链接库(Static Libar ...
- VC++ DLL 2 静态链接库
这一篇以VS2013为例子介绍怎样编写一个静态链接库和调用. 1.打开VS2013,新建Visual C++ 的win32项目: 新建后工程分支如下: 添加头文件和源文件: 编写头文件和源文件内容: ...
- Qt DLL总结【三】-VS2008+Qt 使用QPluginLoader访问DLL
目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...
- Qt DLL总结【二】-创建及调用QT的 DLL(三篇)good
目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...
- Qt 共享库(动态链接库)和静态链接库的创建及调用
前言: 编译器 Qt Creator, 系统环境 win7 64 位 1.创建共享库: 新建文件或项目->选择 Library 和 c++ 库->选择共享库->下一步(工程名为 sh ...
- QtCreator中使用链接库
说明 之前讨论的DLL的静态链接和动态连接都是基于 MSVC 编译器,但是 MinGW 似乎有另外一套类似但是不相同的机制.下文均在 windows 下使用 Qt Creator 中使用 MinGW ...
- linux下静态链接库和动态链接库
关于链接库的知识,网上太多资料了,但是并不代表我很熟悉.今天遇到了 一个问题,就是由于静态链接库和ubuntu系统不兼容导致的,虽然花了点时间才搞定 但是,其中暴露的问题也不少. 没有区分好静态链接库 ...
- lib静态链接库,dll动态链接库,h文件
最近在弄摄像头,发现我在调用摄像头自带的函数的时候,库没连接上,于是经过高人指点,学习了一下lib静态链接库,dll动态链接库来补充一下自己的基础知识. 一.首先我们来介绍一下lib静态链接库. li ...
- Qt Library 链接库
官方教程:http://wiki.qt.io/How_to_create_a_library_with_Qt_and_use_it_in_an_application http://qimo601.i ...
随机推荐
- footer始终在页面最底部的方法(问题待检验)
一.css方法 <style type="text/css"> html,body{ height: 100%; } body{ display: flex; flex ...
- 客户想要的 vs 客户实际预算:漫画解读软件开发模式
转自:http://blog.jobbole.com/113230/ 1913 年,美利坚工业之神——亨利福特,发明了世界上第一条流水线,汽车工业从此进入了大规模生产的时代.丰田公司提出的丰田生产系统 ...
- 使用Leangoo玩转故事地图
转自:https://www.leangoo.com/9944.html 用户故事是在敏捷开发中表达需求的主要方式,我们在做敏捷开发的时候都有需求池的概念,在Scrum中这个需求池就是产品backlo ...
- SAP成都研究院李三郎:SCP Application Router简介
今天的文章来自李贝宁(Ben),SAP成都研究院的资深程序猿和架构师. 作为成都研究院里同时精通Java, JavaScript和ABAP这三门编程语言的数位同事之一,Ben曾经先后担任了成都CRM ...
- Java虚拟机内存基础、垃圾收集算法及JVM优化
1 JVM 简单结构图 1.1 类加载子系统与方法区 类加载子系统负责从文件系统或者网络中加载 Class 信息,加载的类信息存放于一块称 为方法区的内存空间.除了类的信息外,方法区中可能还会存放 ...
- 【Struts2】Ognl与ValueStack
一.OGNL 1.1 概述 1.2 OGNL 五大类功能 1.3 演示 二.ValueStack 2.1 概述 2.2 ValueStack结构 2.3 结论 2.3 一些问题 三.OGNL表达式常见 ...
- 玩转springcloud(一):什么是Springcloud ,有什么优缺点? 学习顺序是什么?
一.首先看官方解释: Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线).分布式系统的协调导致了样板模式, 使 ...
- Linux学习笔记(二)Linux常用命令:权限、目录操作以及常见目录作用
一.Linux命令格式 命令 [选项] [参数] 注:(1)简化选项和完整选项 -a --all (2)当有多个选项是可以写在一起 -l -a 可以写为-la 二.权限 -rw-r--r--.&quo ...
- Hive正则表达式
正则表达式基本语法 用圆括号将所有选择项括起来,相邻的选择项之间用|分隔.但用圆括号会有一个副作用,使相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用. 其中 ?: 是非捕获元之一,还 ...
- Swagger保姆级教学
Swagger保姆级教学 Swagger 简介 Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样 ...