Windows下动态链接库和静态链接库的生成以及调用

一、简介

为了提高代码的复用性,引入了库,库是一段可执行代码的二进制形式,可以被操作系统直接载入内存使用。一般分为动态库和静态库,在Windows操作系统中静态库是以 .lib 为后缀的文件,动态库是以 .dll 为后缀的文件。

C++程序编译以及调用库的过程如下:
在这里插入图片描述
可以看到库是在链接过程和目标文件一起打包最终生成可执行文件,另外可以看到静态库和动态库是编译型语言所特有的,对于非编译型语言例如python,在实现上有所不同。
以下是静态链接库和动态链接库的区别:

1. 静态链接库(.lib):在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中,相当于在可执行文件中每个用到库的地方,都会插入一份库的代码,这样会增加最终生成的可执行文件的体积。
2. 动态链接库(.dll):在链接阶段,动态库并不会被插入到目标文件.o中,而是在.exe可执行文件运行时才会被加载到内存,然后被程序调用,这样能大大减小生成的可执行文件的体积,并且动态链接库被修改时,并不需要重新编译生成源代码。

二、生成静态链接库(.lib)和动态链接库(.dll)

  1. 首先使用vs2019新建空项目,命名选择存储位置。
    在这里插入图片描述
  2. 在项目中新建空白 .h 头文件和 .cpp 源文件,如下:
    在这里插入图片描述
  • .h 头文件输入以下代码:
// addnum.h
#ifndef __ADDNUM_H__
#define __ADDNUM_H__

extern "C" {
	_declspec(dllexport) int AddTwoInt(int a, int b);
}
#endif // !__ADDNUM_H__
  • .cpp 源文件输入以下代码:
// addnum.cpp
#include "addnum.h"
int AddTwoInt(int a, int b)
{
	return a + b;
}
  • 其中.h 头文件中extern “C” 表示使用C语言方式生成链接库,而_declspec(dllexport)用于声明库函数,.cpp源文件是该函数的具体实现过程,AddTwoInt()函数的功能是计算两个整形数之和。
  1. 点击项目->属性->常规->配置类型,设置当前项目的生成类型。如下图:
    在这里插入图片描述
    可以看到,这里可以选择生成的类型,如果要生成静态链接库,选择静态库,如果要生成动态链接库,选择动态库,选择之后点击确定即可。

  2. 点击生成,生成解决方案,然后就会在相应文件夹下生成库文件,如下:

  • 生成静态库(.lib)
    在这里插入图片描述
  • 生成动态库(.dll)
    在这里插入图片描述
    生成了对应的动态库和静态库之后,下面就可以编写源程序来调用库。

三、静态链接库的调用

相较于动态链接库,静态链接库的调用相对简单,我们只需要在调用函数中声明好静态库中的函数接口,即可完成调用。

  1. 首先还是使用vs2019新建一个空项目,然后在项目下新建 addnum.h 和 main.cpp 文件,其中addnum.h 文件是对库的函数接口的说明,main.cpp 调用库函数。代码分别为:
  • addnum.h文件:
// addnum.h
#ifndef __ADDNUM_H__
#define __ADDNUM_H__
extern "C" {
	_declspec(dllimport) int AddTwoInt(int a, int b);
}
#endif // !__ADDNUM_H__
  • main.cpp文件:
// main.cpp
#include <iostream>
#include "addnum.h"
using namespace std;
int main() {
	cout << AddTwoInt(7, 19) << endl;
	return 1;
}
  • addnum.h文件主要声明AddTwoInt()函数是从外部库导入的,main()函数调用AddTwoInt()函数计算"7+19"的结果。
  1. 将之前生成的libtest.lib静态链接库添加到项目的资源文件,完成后如下:
    在这里插入图片描述
  2. 按Ctrl+F5或者点击调试->开始执行,运行源代码,得到结果如下:
    在这里插入图片描述
    可以看到程序返回结果为26,说明调用成功。

四、动态链接库的调用

动态链接库的两种调用方式

相对于调用静态库,调用动态库的过程更加复杂。主要由两种方法:

  • 第一种方法是仅使用之前编译生成的.dll动态链接库文件,程序在运行时将库直接加载到内存中,获取函数的入口地址,然后利用函数指针直接调用。
  • 第二种方法是使用编译动态库过程中产生的静态库,这个静态库是系统自动生成的,其内部并不包含函数接口,作用只是获得动态库的函数地址,使得可以像调用静态库一样调用动态库。

仅使用.dll文件

  1. 同样的,首先新建一个空项目,在项目中新建一个.cpp源文件以及将之前生成的.dll动态库文件添加到项目文件夹下以及项目中,如下:
    在这里插入图片描述
  • main.cpp中的代码:
// main.cpp
#include <iostream>
#include <Windows.h>
using namespace std;

typedef int (*pAddTwoInt)(int, int);     //对应的函数指针类型,指向AddTwoInt()函数在内存中的入口地址

int main()
{
	HMODULE hdll;   //动态链接库的句柄
	hdll = LoadLibrary("libtest.dll");    //加载动态链接库,返回其句柄
	if (hdll == NULL)
	{
		cout << "lib load failed!" << endl;
		return 1;
	}
	pAddTwoInt fAddTwoInt = (pAddTwoInt)GetProcAddress(hdll, "AddTwoInt");  //获取动态链接库中AddTwoInt()函数的入口地址
	cout << fAddTwoInt(7, 19) << endl;       //调用获取到的函数计算结果
	FreeLibrary(hdll);     //调用结束,在内存中释放动态库
	return 1;
}

  • 运行,得到结果如下:
    在这里插入图片描述

使用.h+.dll+.lib文件

这种方法调用需要使用编译生成动态链接库时自动生成的静态库,调用方法类似调用静态库,但是本质上却是使用的动态库。

  1. 同样的,首先新建一个空项目,在项目下添加addnum.h和main.cpp文件,然后将生成的动态库和静态库都复制到项目文件夹下,以及添加到项目,如下:
    在这里插入图片描述
  2. 由于这里调用动态库的方法和调用静态库一样,因此此处addnum.h和main.cpp的内容页数一样的,如下:
  • addnum.h文件:
// addnum.h
#ifndef __ADDNUM_H__
#define __ADDNUM_H__
extern "C" {
	_declspec(dllexport) int AddTwoInt(int a, int b);
}
#endif // !__ADDNUM_H__
  • main.cpp文件:
// main.cpp
#include <iostream>
#include "addnum.h"
using namespace std;

int main()
{
	cout << AddTwoInt(7, 19) << endl;
	return 1;
}
  1. 运行,结果如下:
    在这里插入图片描述
    也成功的得到了结果。
  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
动态链接库(Dynamic Link Library,DLL)和静态库(Static Library)都是常见的库文件形式,用于在编程中重用代码。 静态库是一组已经编译好的对象文件的集合,它们被静态地链接到可执行文件中。在编译时,静态库的代码会被复制到可执行文件中,因此可执行文件本身包含了所有需要的代码。静态库的优点是方便部署,因为可执行文件独立于外部依赖,不需要额外的库文件。但是,静态库的缺点是每个可执行文件都会包含一份代码副本,因此可能会造成代码冗余和文件体积较大。 动态链接库是一组已经编译好的对象文件的集合,它们在运行时被动态地加载到内存中。在编译时,可执行文件只包含对动态链接库的引用,而不是实际的代码。在程序运行时,操作系统会根据引用去查找并加载相应的动态链接库动态链接库的优点是节省内存空间,因为多个可执行文件可以共享同一个动态链接库的实例。此外,如果动态链接库发生更新或修复,只需要替换库文件本身而无需重新编译可执行文件。然而,动态链接库的缺点是部署时需要额外的库文件,而且对于不同的操作系统和体系结构可能需要不同的库文件。 在C#中,动态链接库通常采用.dll后缀,而静态库通常采用.lib后缀。可以使用.NET平台的工具(如C#编译器或Visual Studio)来编译和生成库文件。对于动态链接库,可以使用DllImport属性或者使用.NET平台提供的InteropServices命名空间中的相关类来引用和调用其中的函数。对于静态库,可以将其链接到可执行文件中,或者使用.NET平台提供的工具(如ILMerge)将其合并到可执行文件中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值