静态链接库(.lib)和动态链接库(.dll)的使用

article/2025/9/29 9:09:06

静态链接库(.lib)和动态链接库(.dll)的使用

文章目录

    • 静态链接库(.lib)和动态链接库(.dll)的使用
      • 一、静态链接库
        • 1. 静态链接库概述
        • 2. 创建静态链接库
        • 3. 调用静态链接库
      • 二、动态链接库(dynamic linking library)
        • 1. 动态链接库概述
        • 2. 创建动态链接库并导出函数
          • 导出函数两种方式
            • 1. 用.def文件导出
            • 2. __declspec(dllexport)关键字导出
        • 3. 从工程中导入dll中的函数
          • 导入函数两种方式
            • 1. 隐式链接
            • 2. 显式链接

注--------本文所有测试均以VS2019为例

一、静态链接库

 

1. 静态链接库概述

  静态链接库是一种资源的集合,包括函数、变量、类等,项目通过与其链接,

调用库中的资源,并且使用静态链接库时,静态链接库会整体塞入exe文件中,

也就是说,仅凭借一个exe(可执行)文件就可运行程序。

  静态链接库不再包含其他静态库或者动态库,而动态链接库可以。

 

2. 创建静态链接库

在创建项目中选静态库即可

例如,想在静态库实现功能如下函数,以备其他项目调用

int add(int a, int b)
{return a + b;
}int sub(int a, int b)
{return a - b;
}

则需要,头文件 + 源文件,头文件用来声明函数原型,源文件用来实现函数功能,

特别地,头文件声明函数原型时,需要在前面加上extern "C"字样,完整例子如下

新建静态链接库项目名称:LibTest

头文件:Inc.h

#pragma once//只编译一次extern "C" 
{int add(int a, int b);int sub(int a, int b);
}

源文件:LibTest.cpp

#include "pch.h"//包含预编译标准头文件,这个文件是一创建项目就有的,如果你选的不是空项目
#include "Inc.h"int add(int a, int b) {return a + b;}
int sub(int a, int b) {return a - b;}

点击生成,显示成功即可,此时,在该项目文件目录下,即LibTest文件下,会多出一个Debug文件夹,里面出现与项目同名.lib文件LibTest.lib

 

3. 调用静态链接库

  1. 头文件包含
  2. 目录链接

  这是调用静态链接库的两个步骤,头文件包含意思是,新项目中必须包含以上静态链接库中函数声明的头文件,即Inc.h,因为这个头文件不在新项目下,所以要带上路径。

  目录链接是用来链接新项目与上面生成的.lib文件,有多种链接方式,这里只用一种方法展示

新项目名称为LibCall,类型为控制台程序,这里为了方便叙述,将新项目与上述生成的lib项目放置在同一个解决方案中,也就是项目LibTest与项目LibCall在同一个文件夹下,如图

1

在LibCall项目的main函数中,进行头文件包含和目录链接操作,如下

main.cpp

#include <iostream>
#include "../LibTest/Inc.h"//头文件包含
#pragma comment(lib, "../LibTest/Debug/LibTest.lib")int main()
{int iRet = add(7, 8);std::cout << "7 + 8 = " << iRet << std::endl;return 0;
}

二、动态链接库(dynamic linking library)

 

1. 动态链接库概述

  动态链接库与静态链接库相似之处在于“库”,是一种资源的集合,包括函数、变量和类,与后者不同的是,它可以包含其他的静态链接库、动态链接库。

  新项目依靠动态链接库运行,那么这个.dll文件自然成了程序的一部分,即便是调试之后,对于生成的exe文件仍不能单独运行,即如果删除目录中的.dll文件,exe文件运行不了,并警报缺少dll。这点与静态链接库不同,因为静态链接库是直接塞入exe中的,删除.lib文件后exe运行照常。

 

2. 创建动态链接库并导出函数

  例如创建了一个名为DllTest的动态链接库项目,只有将在dll中的编写过的函数进行导出才能使用,

所以接下来要导出函数。

导出函数两种方式
1. 用.def文件导出

在项目中新建.def文件,文件内容:

源文件(.def文件):DllTest.def

LIBRARY "DllTest"EXPORTSadd @1

另外:需要文件
头文件:fun.h

#pragma once
int add(int a, int b);

源文件:fun.cpp

#include "pch.h"//预编译头文件
#include "fun.h"int add(int a, int b)
{return a + b;
}

说明:.def文件的第一行必须是LIBRARY "XXX",其中XXX是dll的项目名称,EXPORT下面是导出函数,@1即编号为1,接下来可以按照编号调用函数(本文略过)。当然该文件有特殊的注释形式,如

; This is a 注释,即在要注释的内容前面加上一个分号。

 

2. __declspec(dllexport)关键字导出

头文件:fun.h

#pragma once
extern "C" __declspec(dllexport) int add(int a, int b);

源文件:fun.cpp

#include "pch.h"//预编译头
#include "fun.h"int add(int a, int b) { return a + b;}

 

3. 从工程中导入dll中的函数

导入函数两种方式
1. 隐式链接

​   隐式链接是对生成dll文件时一并生成的同名.lib文件进行操作,方式类似于静态链接

  1. 对用.def文件导出dll的函数,导入函数格式:

    方式一:<1> int add(int a, int b);
    方式二:<2> __declspec(dllimport) int add(int a, int b);
    

    有如上两种形式的声明,均可,完整例子:

    源文件:

    #include <iostream>
    #pragma comment(lib, "../DllTest/Debug/DllTest.lib")//int add(int a, int b)
    __declspec(dllimport) int add(int a, int b);int main()
    {int iRet = add(5, 3);std::cout << "5 + 3 = " << iRet << std::endl;system("pause");return 0;
    }
    
  2. 对用__declspec(dllexport)关键字导出dll的函数,导入函数格式:

    方式一:<1> extern "C" __declspec(dllimport) int add(int a, int b);
    方式二:<2> extern "C" int add(int a, int b);
    

    源文件:

    #include <iostream>
    #pragma comment(lib, "../DllTest/Debug/DllTest.lib")//extern "C" int add(int a, int b);
    extern "C" __declspec(dllimport) int add(int a, int b);int main()
    {int iRet = add(5, 3);std::cout << "5 + 3 = " << iRet << std::endl;system("pause");return 0;
    }
    
2. 显式链接

这里不详细说明了,给出一般过程:

LoadLibrary(…);//该API用于加载指定的DLL

GetProAddress(…);//该API用于获取DLL中导出的函数

FreeLibrary(…); 该API用于卸载指定的DLL

注意:如果一个程序多次调用LoadLibrary()加载同一个dll,那么卸载时也要调用相同次数的

FreeLibrary()卸载。

优点:灵活性强,显式链接是完全由编程者用API加载和卸载的DLL,编程者可以决定什么时候加载、卸载,

以及加载哪个、卸载那个。

这里需要windows API和函数指针的知识,自行百度即可


THE END…


http://chatgpt.dhexx.cn/article/i1V5AA1P.shtml

相关文章

静态链接库

库 库的存在&#xff0c;大大方便了我们进行编程。因为有了库&#xff0c;我们不必再从0开始&#xff0c;例如我们大多数人C语言写的第一个程序Hello World!都是用了库函数。以printf为例&#xff0c;我们只需要在程序源代码中包含<stdio.h>这个头文件之后&#xff0c;就…

史上最全Java类型转换

讲类型转换之前&#xff0c;让我来贴张表 基本数据类型的表示范围 类型 长度 表示范围默认值byte8b-128&#xff5e;1270short16b-32768&#xff5e;327670int32b-21147483648&#xff5e;21474836470long64b-9223372036 854 775 808&#xff5e;9223372036 8547758070Lfloat3…

Java:类型转换

public class Demo04 {public static void main(String[] args) {//低--------------------------> 高// byte,short,char->int->long->float->doubleint i 128;byte b (byte) i ;//内存溢出//强制转换 &#xff08;类型&#xff09;变量名 高--低//自动转换…

java强转规则_java类型转换及其规则介绍

一、自动类型转换 整型、实型(常量)、字符型数据可以混合运算。运算中&#xff0c;不同类型的数据先转化为同一类型&#xff0c;然后进行运算。 数据类型转换必须满足如下规则&#xff1a; 1、不能对boolean类型进行类型转换。 2、不能把对象类型转换成不相关类的对象。 3、在把…

Sql-Java类型转换

Mysql-Java字段类型转换 mysql类型名大小用途对应Java类char0-255 bytes定长字符串 &#xff08;姓名、性别、学号&#xff09;Stringvarchar0-65535 bytes变长字符串&#xff08;比上面更长一点的那种&#xff09;Stringtinytext0-255 bytes比较短的那种文本数据&#xff08;…

JAVA类型转换及变量详解

类型转换 由于java是强类型语言&#xff0c;所以要进行有些运算的时候&#xff0c;需要用到类型转换。 byte&#xff08;1个字节&#xff09;,short&#xff08;2个字节&#xff09;,char&#xff08;2个字节&#xff09;----->int&#xff08;4个字节&#xff09;---->…

Java类型转换(自动类型转换+强制类型转换)

一、 自动类型转换(隐式类型转换) 整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。自动转换从低级到高级。 自动转换有以下规律: 1、小的类型自动转化为大的类型 2、整数类型可以自动转化为浮点类型,可能会产生舍入误…

Java的类型转换

需要类型转换的原因:因为Java是强类型的语言&#xff0c;所以有时可能要进行跨类型的运算&#xff0c;这就需要先进行类型转换&#xff0c;再进行运算。 类型转换分为&#xff1a; 强制类型转换(由高-->低时使用)&#xff0c;自动类型转换/ 隐式类型转换(由低-->高时使用…

java中的类型转换

java的基本数据类型 1.数值型&#xff1a;byte&#xff0c;short&#xff0c;int&#xff0c;long&#xff0c;float&#xff0c;double 2.字符型&#xff1a;char 3.布尔型&#xff1a;boolean 数据类型占据字节数byte1个字节short2个字节int4个字节long8个字节float4个字节…

Java中各种类型的转化

目录 一.Integer和int之间的类型转化 1.自动装箱 2.构造器方法 3.Integer.valueOf(int i) 二.Integer和String之间的类型转换 1.String转换为Integer 1.Integer.parseInt(String s) ​编辑 2.Integer.valueOf(String s) 2.Integer转换为String 1.Integer.toString() …

【JAVA】Java中的类型转换

目录 1.自动类型转换&#xff08;隐式转换&#xff0c;小类型转换为大类型&#xff09; 2.强制类型转换&#xff08;显示转换&#xff0c;大类型转换为小类型&#xff09; 3.小于4字节的类型转换问题 3.1 byte<->int 3.2 char<->int 3.3 String<->int …

Java 类型转换

一、自动类型转换(隐式类型转换) 整型、实型(常量)、字符型数据可以混合运算。不同类型的数据先转化为同类型再进行运算 自动转换按从低级到高级顺序: char ↓ Byte→short→int→long---›float→double 自动转换有以下规律&#xff1a; 小的类型自动转化为大的类型 整数…

java类型转换

文章目录 1、什么是类型转换&#xff1f; 2、掌握常见数据类型的范围大小 3、自动类型转换 3.1 int转换为double 3.2 char转换为int类型 4、强制类型转换 4.1、强制类型转换格式 5、注意事项 1、什么是类型转换&#xff1f; 在java中类型转换是一个非常重要的知识点。因…

java中常见类型的转换以及方法总结

1.char、String、int类型之间的转换 1.1 char和String的区别 char是表示的是字符&#xff0c;定义的时候用单引号&#xff0c;只能存储一个字符。例如; char‘d’. String表示的是字符串&#xff0c;定义的时候用双引号&#xff0c;可以存储一个或者多个字符。例如&#xff1…

CentOs 无法启动网络,用ip addr看不到IP地址

1.无法启动网卡&#xff0c;启动报file exist 原因1&#xff1a;可能是别的网络与网络冲突 解决&#xff1a;关闭NetworkManager 原因2&#xff1a;etc/sysconfig/network-scripts下的ifcfg开头的文件有内容有冲突 解决&#xff1a;删除一些对应文件 如果还是不行&#xf…

ip命令的使用方式(临时设定:ip addr ,ifconfig)

对外开放&#xff0c;能和主机直接进行交流的设备叫做网卡 内部交流&#xff0c;系统内部服务与服务之间的接口&#xff0c;为回环接口 lo##回环设备 [rootlocalhost 桌面]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default…

ifconfig、ip addr、ip route用法总结

最近使用haproxykeepalived 负载均衡&#xff0c;发现虚拟IP有问题&#xff0c;配置文件里配的VIP是.4.143 ,但是执行 ip a 发现还有一个虚拟IP.4.134&#xff1b;应该是以前配置文件keepalived.conf里设置过VIP .4.134 以前的VIP一直没有消除&#xff0c;手动清除VIP&#xff…

Centos7中查看IP命令:IP addr

开机&#xff0c;输入用户名root和上篇文章中设置的密码&#xff0c;&#xff08;密码在Linux中是看不见的&#xff0c;但确实已经输入了&#xff09;&#xff0c;回车确定&#xff0c;显示时间信息&#xff08;没有设置时间&#xff09;&#xff0c;表示登陆成功。 在Centos7中…

openEuler 知:ip addr 查不到 ip 的解决方法

通过 VMware Workstation 安装 openEuler 虚拟机后&#xff0c;通过 ip addr 查不到 ip&#xff0c;如下所示&#xff1a; 备注&#xff1a;默认没有安装 ifconfig 命令。 解决方法&#xff1a; 进入 /etc/sysconfig/network-scripts 目录&#xff0c;在文件路径下找到 ifcf…

【Linux命令】ifconfig、route、ip route、ip addr、 ip link 用法 一

文章目录 1. 前言2. ifconfig2.1 配置地址2.2 查看功能2.2.1 ifconfig 查看不含禁用的网卡2.2.2 ifconfig -a 查看含禁用的网卡2.2.3 ip a 2.3 启用、禁用网卡2.3.1 ifconfig eth1 up、 ifconfig eth1 down2.3.2 ifdown eth0、ifip eth0 2.4 扫描eth0接口的数据2.5 网卡别名2.5…