Dll的创建与使用


首先提出几个问题,什么是库文件、什么是静态库、什么是动态库,在windows中经常有看到.dll和.lib文件,他们是什么?

库、静态库、动态库

  库是写好的,现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,
不可能每个人的代码都从零开始,因此库的存在意义非同寻常。本质上来说,库是一种可执行代码的二进制形式,
可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。所谓静态、动态是指
链接。

  lib(静态库)与dll(动态库)文件最大区别在调用方面,可以简单的理解为一个程序在运行的时候,
到哪里去找它需要的函数。如果链接的是静态库,那么在程序的编译链接过程中库已经嵌入进程序中了,此时程序
中已经包含了所有库函数的实现,那么就不需要到处找了。如果链接的是动态库,那么程序在运行过程中需要调用
到库函数的时候,这个时候程序中只有库函数的位置(指示程序应该到哪里去找到这个函数),没有库函数的实现。

  动态链接与静态链接的不同之处在于:动态链接允许可执行模块(.dll 文件或 .exe 文件)仅包含在运行时定位 DLL 函数的可执行代码所需的信息。在静态链接中,链接器从静态链接库获取所有被引用的函数,并将库同代码一起放到可执行文件中。

参考链接

windows下.lib与.dll的关系

  1. lib是编译时需要的,dll是运行时需要的。
    如果要完成源代码的编译,有lib就够了。
    如果也使动态连接的程序运行起来,有dll就够了。
    在开发和调试阶段,当然最好都有。

  2. 一般的动态库程序有lib文件和dll文件。lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。

  3. 在动态库的情况下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。

开发和使用dll需注意三种文件

dll头文件(.h)

它是指dll中说明输出的类或符号原型或数据结构的.h文件。当其它应用程序调用dll时,需要将该文件包含入应用程序的源文件中。

dll的引入库文件(.lib)

它是dll在编译、链接成功后生成的文件。主要作用是当其它应用程序调用dll时,需要将该文件引入应用程序。否则,dll无法引入。

dll文件(.dll)

它是应用程序调用dll运行时,真正的可执行文件。dll应用在编译、链接成功后,.dll文件即存在。开发成功后的应用程序在发布时,
只需要有.exe文件和.dll文件,不必有.lib文件和dll头文件。

动态链接库(DLL)是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。
函数的可执行代码位于一个 DLL中,该DLL包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。
DLL还有助于共享数据和资源。多个应用程序可同时访问内存中单个DLL副本的内容。

参考链接1:lib和dll文件的区别和联系

Dll的创建与使用

说明: 实例中使用的代码来自leetcode 224. 基本计算器

STEP1: 创建DLL项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

STEP2: 代码编写

在这里插入图片描述

//Solution.h
#pragma once

#include<string>
#include<vector>

#ifdef DLL2_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif // DLL2_EXPORTS



class DLL_API Solution { //这个地方说明我们要将Solution这个class导出到Dll中
public:
    int calculate(std::string s);
};

这里有必要说明一下,我们创建的Dll项目名为Dll2,则VS会自动帮我们预定义Dll2_EXPORTS宏,所以当我们编译
Dll项目的时候Dll_API展开为__declspec(dllexport),而当我们引用Dll库的时候由于没有预定DLL2_EXPORTS
宏,所以Dll_API展开为__declspec(dllimport)。可以通过项目–>属性–>C/C+±->预处理器–>预处理器定义看到VS为我们预定义的宏

在这里插入图片描述

#include"Solution.h"

int Solution::calculate(std::string s) {
    int ans = 0;
    int sign = 1;
    std::vector<int> stk{ 1 };
    for (int i = 0, e = s.length(); i < e;) {
        if (s[i] == ' ') {
            i++;
        }
        else if (s[i] == '(') {
            stk.push_back(sign);
            i++;
        }
        else if (s[i] == ')') {
            stk.pop_back();
            i++;
        }
        else if (s[i] == '-') {
            sign = -stk.back();
            i++;
        }
        else if (s[i] == '+') {
            sign = stk.back();
            i++;
        }
        else {
            long num = 0;
            while (i < e && isdigit(s[i])) {
                num = num * 10 + s[i] - '0';
                i++;
            }
            ans += sign * num;
        }
    }
    return ans;
}

至此代码便编写完成,直接按ctrl+b生成,然后打开项目文件夹我们可以看到生成的Dll2.dll和Dll2.lib,这两个的作用前面已经说明
在这里插入图片描述

STEP3:DLL使用

Dll编写好了之后我们要怎么使用呢?下面通过创建一个新的项目来使用生成的dll
在这里插入图片描述

因为我们要使用Dll库,既然要使用它那么我们就需要知道这个库中有啥东西,通过什么来获取这些信息呢–头文
件,也就是STEP2中的Solution.h。为我们的项目设置附加包含目录,该目录应是Dll头文件的目录
在这里插入图片描述

库是在链接过程中加入的,所以在链接器中告诉我们的链接器我们的库在哪个文件(附加库目录应是Dll编译出来的.lib所在的目录)
在这里插入图片描述

添加了库目录之后说明需要使用的库名称,此处为Dll2.lib
在这里插入图片描述

所有配置都设置好了之后就是编写代码使用库了

#include<iostream>
#include<string>
#include"Solution.h"

int main() {
	std::string str{ "(1+(4+5+2)-3)+(6+8)" };
	Solution solution;
	std::cout << solution.calculate(str) << std::endl;
}

在这里插入图片描述

代码写好之后直接编译运行,但是这个时候运行会提示找不到相应的dll,前面我们说过dll是在程序运行过程中动
态加载的,但是我们的程序并不知道这个dll的目录在哪所以会报错
在这里插入图片描述

解决办法之一是将生成的dll复制到该项目生成的exe目录下,这也就可以理解了为何发布软件的时候要连dll也一并
发布。解决办法之二是设置环境变量项目-->属性-->配置属性-->调试-->环境在那一栏中添加PATH=path/to/you/dll;%PATH%
在这里插入图片描述

一切就绪后终于得到了正确的结果。
在这里插入图片描述

参考链接:创建和使用自己的动态链接库 (C++)

创建并使用静态库

前面我们创建了动态链接库,那么静态库如何创建呢?相对与动态库来说,静态库的创建与使用步骤差不多

STEP1:创建静态库项目

在这个地方我将静态库项目和之前创建的动态库项目放在一起
在这里插入图片描述
在这里插入图片描述

STEP2:代码编写

将静态库项目命名为StaticLib1,那么之后会生成StaticLib1.lib,如之前那般删除掉不必要的文件,静态库不
需要像动态库那般使用__declspec(...),与平常写代码无差别,编写头文件.h,实现.cpp

//StaticLib1.h
#pragma once

#include<string>
#include<vector>

class Solution1 {
public:
    int calculate(std::string s);
};
// StaticLib1.cpp : 定义静态库的函数。

#include"StaticLib1.h"

int Solution1::calculate(std::string s) {
    int ans = 0;
    int sign = 1;
    std::vector<int> stk{ 1 };
    for (int i = 0, e = s.length(); i < e;) {
        if (s[i] == ' ') {
            i++;
        }
        else if (s[i] == '(') {
            stk.push_back(sign);
            i++;
        }
        else if (s[i] == ')') {
            stk.pop_back();
            i++;
        }
        else if (s[i] == '-') {
            sign = -stk.back();
            i++;
        }
        else if (s[i] == '+') {
            sign = stk.back();
            i++;
        }
        else {
            long num = 0;
            while (i < e && isdigit(s[i])) {
                num = num * 10 + s[i] - '0';
                i++;
            }
            ans += sign * num;
        }
    }
    return ans;
}

在这里插入图片描述
在这里插入图片描述

代码编写好之后直接ctrl+b编译生成,之后可以在项目文件夹下看到生成的StaticLib1.lib
在这里插入图片描述

STEP3:使用静态库

下面我们将之前使用动态库的项目改为使用静态库

  1. 设置头文件(附加包含目录)
  2. 设置附加库目录(*.lib所在的目录)
  3. 设置附加依赖项

在这里插入图片描述
在这里插入图片描述

配置好之后直接上代码,编译运行就可以了,使用静态库已经不需要用到dll了,因为代码的实现已经在lib中了,而且可以看到静态库生成的只有.lib没有.dll。
在这里插入图片描述
在这里插入图片描述

参考链接:创建并使用静态库

  • 15
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值