2021-05-07 17:43发布
静态链接库DLL,动态连接库概念以及使用dll的好处:
静态连接库
静态连接库:Window下以*.lib Linux下以*.a 命名的文件统称;
静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序发布运行的时候不再需要其它的库文件
动态连接库
动态连接库(Dynamic-link Library,缩写为 DLL):Window下以*.dll Linux下以*.so 命名的文件统称;
动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此在发布和运行时需要相应DLL文件的支持
分析
分隔符上边是优点下边是缺点
静态链接库 动态链接库
代码装载速度快,执行速度略比动态链接库快 更加节省内存并减少页面交换
只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱等问题 DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性
不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数
适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试
使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;是将全部指令包含到可执行程序,要么全要要么全不要 应用程序不是自完备的,依赖的DLL模块必须存在。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要修改旧模块才能运,会造成"DLL地狱"
无论动态库还是静态库都包含 .lib文件
我接触的大多是使用动态链接库,静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.a更新了,所以使用它的应
用程序都需要重新编译、发布给用户(对于客户来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存
里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和
发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
静态链接库调用
静态链接库的使用比较简单需要库的开发者提供生成库的.h头文件和.lib文件。生成库的.h头文件中的声明格式如下:
extern "C" 函数返回类型 函数名(参数表);
在调用程序的.cpp源代码文件中如下:
#include "../lib.h"
#pragma comment(lib,"..//debug//libTest.lib") //指定与静态库一起链接
需要的文件: 头文件 .h 、静态库 .lib
头文件.h中有函数的声明,使用静态链接库的项目需要引用该文件才能编译通过
lib包含了实际执行代码、符号表等等
加载lib的方法: 法1.使用编译链接参数或者VS的配置属性来设置 法2.使用pragma编译语句,例如pragma comment(lib,“a.lib”)
lib中的指令将全部被直接包含在最终生成的 EXE 文件中
动态链接库俩种调用方式
动态链接库的调用方式有俩种比较拗口:静态调用(隐式加载) 和 动态调用(显示加载)
先来说比较常用和简单的隐式加载
需要生成的 lib dll .h 文件 三者缺一不可,配置如下:
vs项目->属性->VC++目录->包含目录:添加头文件所在路径
vs项目->属性->VC++目录->库目录:添加lib文件所在路径
DLL复制到exe执行目录
此处我有个疑问有懂得大佬可以帮我解答下:为什么有的还需要在链接器->附加依赖项中添加 lib文件的全称
什么情况下添加?添加的作用? 是和导出方式有关么
和静态库有什么区别:其实这里生成的 lib 文件是很小的。 它只保存了 dll 文件的符号信息,保证 exe 链接的时候能找到要链接的符号,而运行的时候才是真正加载 dll 来调用函数。静态库的话是会把所有实现都会生成 lib 文件,所以静态的 lib 文件是很大的。
优点:
1.不需要动态加载 dll 文件和释放。在写代码的时候引入了头文件,对于 dll 导出的函数和数据结构看起来比较清晰。
缺点:
1.因为隐式加载的 dll 是在 main 函数之前,所以如果缺少了 dll 会影响 exe 的启动。
显式加载
这里大概可以分这几步:1.加载dll文件,2。取得文件内相应函数的指针。3.使用函数。4.释放dll句柄
只需要生成的 dll 文件 ,但是loadLibrary之后可以使用getProcAddress来查找一个函数的地址从而调用该函数,必须知道函数的类型,名称,参数
typedef int(__cdecl* FunctionAdd)(int,int); // 声明相应的函数指针类型。
HMODULE hModule; // 指向dll文件的句柄。
FunctionAdd add; // 指向相应函数的指针实例。
hModule = LoadLibrary("dll1.dll"); // LoadLibrary 将dll1.dll文件加载进内存中来。用句柄指向。文件目录可以任意。
If(NULL==hModule )
{
//error.
}
add =(FunctionAdd)GetProcAddress(hModule,"add"); //根据dll的句柄得到相应函数的指针。
if(NULL==add)
//error
int r = add(1,1) ; // 得到指针后就可以用相应的函数啦。
Wsprintf msgbox
FreeLibrary(hModule); // 释放dll句柄。
1.不需要在 exe 链接的时候放入对应的 lib。
2.加载的 dll 在 main函数之后,是由用户主动操作,可操作空间大。
3.就算目标 dll 丢失,也只会导致 LoadLibrary加载失败,根据业务逻辑来判断是否影响主逻辑。
4.支持热更新,更新了 dll,在进程内部调用 FreeLibrary 然后调用LoadLibrary 加载新的 dll,而不用重启进程。
1.调用之前需要清楚的知道导出函数的定义,来定义函数指针指向它。需要手动加载和释放,如果漏掉了释放可能会造成资源泄露。
根据需求来选择加载模式,比如这个 dll 是程序的主模块,没有的话程序就不能启动,使用隐式加载。而比如dll可能就只是一个插件,这样就可以使用显示加载
声明一个导出函数,是说这个函数要从本DLL导出。我要给别人用。一般用于dll中省掉在DEF文件中手工定义导出哪些函数
的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类
声明一个导入函数,是说这个函数是从别的DLL导入。我要用。一般用于使用某个dll的exe中 不使用 __declspec(dllimport)
也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因
为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL
边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。
最多设置5个标签!
静态链接库DLL,动态连接库概念以及使用dll的好处:
静态连接库
静态连接库:Window下以*.lib Linux下以*.a 命名的文件统称;
静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序发布运行的时候不再需要其它的库文件
动态连接库
动态连接库(Dynamic-link Library,缩写为 DLL):Window下以*.dll Linux下以*.so 命名的文件统称;
动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此在发布和运行时需要相应DLL文件的支持
分析
分隔符上边是优点下边是缺点
静态链接库 动态链接库
代码装载速度快,执行速度略比动态链接库快 更加节省内存并减少页面交换
只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱等问题 DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性
不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数
适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试
使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;是将全部指令包含到可执行程序,要么全要要么全不要 应用程序不是自完备的,依赖的DLL模块必须存在。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要修改旧模块才能运,会造成"DLL地狱"
无论动态库还是静态库都包含 .lib文件
我接触的大多是使用动态链接库,静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.a更新了,所以使用它的应
用程序都需要重新编译、发布给用户(对于客户来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存
里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和
发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
静态链接库调用
静态链接库的使用比较简单需要库的开发者提供生成库的.h头文件和.lib文件。生成库的.h头文件中的声明格式如下:
extern "C" 函数返回类型 函数名(参数表);
在调用程序的.cpp源代码文件中如下:
#include "../lib.h"
#pragma comment(lib,"..//debug//libTest.lib") //指定与静态库一起链接
需要的文件: 头文件 .h 、静态库 .lib
头文件.h中有函数的声明,使用静态链接库的项目需要引用该文件才能编译通过
lib包含了实际执行代码、符号表等等
加载lib的方法: 法1.使用编译链接参数或者VS的配置属性来设置 法2.使用pragma编译语句,例如pragma comment(lib,“a.lib”)
lib中的指令将全部被直接包含在最终生成的 EXE 文件中
动态链接库俩种调用方式
动态链接库的调用方式有俩种比较拗口:静态调用(隐式加载) 和 动态调用(显示加载)
先来说比较常用和简单的隐式加载
需要生成的 lib dll .h 文件 三者缺一不可,配置如下:
vs项目->属性->VC++目录->包含目录:添加头文件所在路径
vs项目->属性->VC++目录->库目录:添加lib文件所在路径
DLL复制到exe执行目录
此处我有个疑问有懂得大佬可以帮我解答下:为什么有的还需要在链接器->附加依赖项中添加 lib文件的全称
什么情况下添加?添加的作用? 是和导出方式有关么
和静态库有什么区别:其实这里生成的 lib 文件是很小的。 它只保存了 dll 文件的符号信息,保证 exe 链接的时候能找到要链接的符号,而运行的时候才是真正加载 dll 来调用函数。静态库的话是会把所有实现都会生成 lib 文件,所以静态的 lib 文件是很大的。
优点:
1.不需要动态加载 dll 文件和释放。在写代码的时候引入了头文件,对于 dll 导出的函数和数据结构看起来比较清晰。
缺点:
1.因为隐式加载的 dll 是在 main 函数之前,所以如果缺少了 dll 会影响 exe 的启动。
显式加载
这里大概可以分这几步:1.加载dll文件,2。取得文件内相应函数的指针。3.使用函数。4.释放dll句柄
只需要生成的 dll 文件 ,但是loadLibrary之后可以使用getProcAddress来查找一个函数的地址从而调用该函数,必须知道函数的类型,名称,参数
DLL复制到exe执行目录
typedef int(__cdecl* FunctionAdd)(int,int); // 声明相应的函数指针类型。
HMODULE hModule; // 指向dll文件的句柄。
FunctionAdd add; // 指向相应函数的指针实例。
hModule = LoadLibrary("dll1.dll"); // LoadLibrary 将dll1.dll文件加载进内存中来。用句柄指向。文件目录可以任意。
If(NULL==hModule )
{
//error.
}
add =(FunctionAdd)GetProcAddress(hModule,"add"); //根据dll的句柄得到相应函数的指针。
if(NULL==add)
{
//error
}
int r = add(1,1) ; // 得到指针后就可以用相应的函数啦。
Wsprintf msgbox
FreeLibrary(hModule); // 释放dll句柄。
优点:
1.不需要在 exe 链接的时候放入对应的 lib。
2.加载的 dll 在 main函数之后,是由用户主动操作,可操作空间大。
3.就算目标 dll 丢失,也只会导致 LoadLibrary加载失败,根据业务逻辑来判断是否影响主逻辑。
4.支持热更新,更新了 dll,在进程内部调用 FreeLibrary 然后调用LoadLibrary 加载新的 dll,而不用重启进程。
缺点:
1.调用之前需要清楚的知道导出函数的定义,来定义函数指针指向它。需要手动加载和释放,如果漏掉了释放可能会造成资源泄露。
根据需求来选择加载模式,比如这个 dll 是程序的主模块,没有的话程序就不能启动,使用隐式加载。而比如dll可能就只是一个插件,这样就可以使用显示加载
声明一个导出函数,是说这个函数要从本DLL导出。我要给别人用。一般用于dll中省掉在DEF文件中手工定义导出哪些函数
的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类
声明一个导入函数,是说这个函数是从别的DLL导入。我要用。一般用于使用某个dll的exe中 不使用 __declspec(dllimport)
也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因
为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL
边界的函数调用中。但是,必须使用 __declspec(dllimport) 才能导入 DLL 中使用的变量。
一周热门 更多>