引言
在Windows开发环境中,lib(静态库)和dll(动态链接库)是两种常见的库文件类型。它们在程序开发和部署中扮演着重要角色,两者都是代码共享的方式,但在生成和使用上有显著的区别。
一、静态库(lib) 和 动态库(dll) 的区别
1. 定义
静态库:在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中,这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝 ;缺点就是被多次使用就会有多份冗余拷贝。即静态库中的指令都全部被直接包含在最终生成的 EXE 文件中了。在vs中新建生成静态库的工程,编译生成成功后,只产生一个.lib文件
动态库:动态链接库是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。在vs中新建生成动态库的工程,编译成功后,产生一个.lib文件和一个.dll文件
那么上述静态库和动态库中的lib有什么区别呢?
静态库中的lib:该LIB包含函数代码本身(即包括函数的索引,也包括实现),在编译时直接将代码加入程序当中
动态库中的lib:该LIB包含了函数所在的DLL文件和文件中函数位置的信息(索引),函数实现代码由运行时加载在进程空间中的DLL提供
2. 链接方式
- 静态链接:编译器在编译阶段将lib文件的代码直接合并到可执行文件中。因此,生成的可执行文件体积较大,但在运行时不依赖外部库文件。
- 动态链接:编译器在编译阶段仅包含对dll的引用,而实际代码在运行时加载。这使得可执行文件体积较小,但依赖于dll文件的存在和正确配置。
3. 更新和维护
- 静态库:更新库文件后,需要重新编译所有使用该库的可执行文件。
- 动态库:只需更新dll文件,不需要重新编译使用该库的可执行文件。
4. 资源使用
- 静态库:每个使用静态库的程序都会独立包含一份库代码,造成内存冗余。
- 动态库:多进程可共享同一个dll实例,节省内存资源。
二、lib 和 dll 的生成
1. 生成静态库(lib)
以Visual Studio为例,生成静态库的步骤如下:
-
创建静态库项目:
- 打开Visual Studio,选择“新建项目”。
- 选择“静态库(.lib)”项目模板,输入项目名称和保存位置。
-
编写代码:
- 添加需要的头文件(.h)和源文件(.cpp)。
- 实现所需的函数和类。
-
编译生成:
- 配置项目属性,确保生成目标是静态库。
- 编译项目,生成的静态库文件通常位于
Debug
或Release
文件夹中,以.lib
为扩展名。
示例代码:
.h文件如下
#ifndef _MYLIB_H_
#define _MYLIB_H_
void fun(int a);
extern int k;
class testclass
{
public:
testclass();
void print();
};
#endif
.cpp文件如下
#include "stdafx.h"
#include "lib.h"
#include <iostream>
void fun(int a)
{
std::cout<<a<<"lib gen\n";
}
int k = 222;
testclass::testclass()
{
std::cout<<"123\n";
}
void testclass::print()
{
std::cout<<"this is testcalss\n";
}
2. 生成动态库(dll)
生成动态库的步骤与静态库类似,但有一些关键差异:
-
创建动态库项目:
- 打开Visual Studio,选择“新建项目”。
- 选择“动态链接库(.dll)”项目模板,输入项目名称和保存位置。
-
编写代码:
- 添加需要的头文件(.h)和源文件(.cpp)。
- 使用宏定义导出函数和类。
-
编译生成:
- 配置项目属性,确保生成目标是动态库。
- 编译项目,生成的动态库文件通常位于
Debug
或Release
文件夹中,以.dll
为扩展名,同时生成对应的.lib
文件(导入库)。
示例代码:
.h如下
//新建生成dll的工程时,vs默认定义了宏DLL_EXPORT,因此,DLL_API 是 __declspec(dllexport),用来导出
//当我们在静态调用dll时,我们包含该头文件,由于没有定义DLL_EXPORT,所以DLL_API是
//__declspec(dllimport),用来导入
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
// 导出类
class DLL_API Cdll {
public:
Cdll(void);
// TODO: 在此添加您的方法。
};
//导出变量,变量在.cpp文件中定义
extern DLL_API int ndll;
//导出函数,加extern "C",是为了保证编译时生成的函数名不变,这样动态调用dll时才能
//正确获取函数的地址
extern "C" DLL_API int fndll(void);
.cpp如下
#include "dll.h"
// 这是导出变量的一个示例
DLL_API int ndll=6;
// 这是导出函数的一个示例。
DLL_API int fndll(void)
{
return 42;
}
// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 dll.h
Cdll::Cdll()
{
return;
}
三、lib 和 dll 的使用
1. 使用静态库
需要.h文件,lib文件
(1)设置项目属性--vc++目录--库目录为lib所在的路径
(2)将lib添加到项目属性--链接器--输入--附加依赖项(或者直接在源代码中加入#pragma comment(lib, “**.lib”))
(3)在源文件中添加.h头文件
然后就像平常一样调用普通函数、类、变量,举例如下:
#include <iostream>
#include "lib.h"
#pragma comment(lib, "lib.lib")
int main()
{
fun(4);
std::cout<<k<<std::endl;
testclass tc;
tc.print();
return 0;
}
2. 使用动态库
隐式链接:需要.h文件,dll文件,lib文件
(1)将dll放到工程的工作目录
(2)设置项目属性--vc++目录--库目录为lib所在的路径
(3)将lib添加到项目属性--链接器--输入--附加依赖项(或者直接在源代码中加入#pragma comment(lib, “**.lib”))
(4)在源文件中添加.h头文件
然后就像平常一样调用普通函数、类、变量
// main.cpp
#include "MyDll.h"
int main() {
MyFunction();
return 0;
}
四、总结
lib和dll是Windows开发中常见的两种库文件,各有优缺点。静态库(lib)在编译时将代码直接包含到可执行文件中,适合对性能和独立性要求较高的场景。动态库(dll)则在运行时加载,便于更新和节省内存资源,适合模块化开发和频繁更新的场景。
理解并掌握lib和dll的生成和使用方法,对于提高开发效率和软件质量至关重要。在实际开发中,根据项目需求选择合适的库文件类型,能有效提升项目的可维护性和性能表现。