深入理解:lib 与 dll

引言

在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为例,生成静态库的步骤如下:

  1. 创建静态库项目

    • 打开Visual Studio,选择“新建项目”。
    • 选择“静态库(.lib)”项目模板,输入项目名称和保存位置。
  2. 编写代码

    • 添加需要的头文件(.h)和源文件(.cpp)。
    • 实现所需的函数和类。
  3. 编译生成

    • 配置项目属性,确保生成目标是静态库。
    • 编译项目,生成的静态库文件通常位于DebugRelease文件夹中,以.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)

生成动态库的步骤与静态库类似,但有一些关键差异:

  1. 创建动态库项目

    • 打开Visual Studio,选择“新建项目”。
    • 选择“动态链接库(.dll)”项目模板,输入项目名称和保存位置。
  2. 编写代码

    • 添加需要的头文件(.h)和源文件(.cpp)。
    • 使用宏定义导出函数和类。
  3. 编译生成

    • 配置项目属性,确保生成目标是动态库。
    • 编译项目,生成的动态库文件通常位于DebugRelease文件夹中,以.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的生成和使用方法,对于提高开发效率和软件质量至关重要。在实际开发中,根据项目需求选择合适的库文件类型,能有效提升项目的可维护性和性能表现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值