【c/c++】静态链接库与动态链接库的联系与区别

一、定义

1.1 静态库(.lib / .a)

一种是LIB包含函数代码本身,在编译时直接将代码加入程序当中,称为静态链接库static link library。

函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件(.EXE文件)。当发布产品时,只需要发布这个可执行文件,并不需要发布被使用的静态库

1.2 动态库(.dll / .so)

一种是LIB包含了函数所在的DLL文件文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library。

在使用动态库的时候,往往提供两个文件:

一个引入库(.lib)文件(也称“导入库文件”)和一个DLL(.dll)文件。虽然引入库的后缀名也是“lib”,但是,动态库的引入库文件和静态库文件有着本质的区别,对一个DLL文件来说,其引入库文件(.lib)包含该DLL导出的函数和变量的符号名,而.dll文件包含该DLL实际的函数和数据。
在使用动态库的情况下,在编译链接可执行文件时,只需要链接该DLL的引入库文件,该DLL中的函数代码和数据并不可复制到可执行文件,直到可执行程序运行时,才去加载所需的DLL,将该DLL映射到进程的地址空间中,然后访问DLL中导出的函数。这时,在发布产品时,除了发布可执行文件以外,同时还需要发布该程序将要调用的动态链接库

Windows 系统平台上你可以将独立的程序模块创建为较小的DLL(Dynamic Linkable Library)文件,并可对它们单独编译和测试。在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。Windows自己就将一些主要的系统功能以 DLL模块的形式实现。Windows为应用程序提供了丰富的函数调用,这些函数调用都包含在动态链接库中。其中有3个最重要的 DLL:

Kernel32.dll,它包含用于管理内存、进程和线程的各个函数;

User32.dll,它包含用于执行用户界面任务(如窗口的创建和消息的传送)的各个函数;

GDI32.dll,它包含用于画图和显示文本的各个函数。

当Windows .exe程序被加载到内存中时,程序中的调用被指向DLL函数的入口,如果DLL不在内存中,系统就将其加载到内存中。当链接Windows程序以产生一个可执行文件时,你必须链接由编程环境提供的专门的 “引入库(import library)”。这些引入库包含了动态链接库名称和所有Windows函数调用的引用信息。链接程序使用该信息在.EXE文件中构造一个表,当加载程序时,Windows使用它将调用转换为Windows函数。

所以无论是动态链接库还是静态链接库,都会有lib文件,下面区别会详细介绍。

二、区别 和 使用

动态库对应的导入库 和 静态库 的区别

引入库和静态库的区别很大,他们实质是不一样的东西。
静态库本身就包含了实际执行代码、符号表等等,而对于引入库而言,其实际的执行代码位于动态库中,引入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。但是引入库文件的引入方式和静态库一样,要在链接路径上添加找到这些.lib的路径。

常见VS工程属性里—链接器—高级—导入库,可设置生成的导入库名字。

动态库 与 静态库 的使用区别

2.1 链接静态库

  1. 需要的文件: 头文件 .h 、静态库 .lib
  2. 头文件.h中有函数的声明,使用静态链接库的项目需要引用该文件才能编译通过
  3. .lib包含了实际执行代码、符号表等等
  4. 加载lib的方法:
  •    法1.使用编译链接参数或者VS的配置属性来设置    
    

1) 添加工程的头文件目录:工程—属性—配置属性—c/c+±–常规—附加包含目录:加上头文件存放目录。

2) 添加文件引用的lib静态库路径:工程—属性—配置属性—链接器—常规—附加库目录:加上lib文件存放目录。

3)然后添加工程引用的lib文件名:工程—属性—配置属性—链接器—输入—附加依赖项:加上lib文件名。

  •   法2.使用pragma编译语句,例如pragma comment(lib,"a.lib")
    
生成库的.h头文件中的声明格式如下:
extern "C" 函数返回类型 函数名(参数表);
在调用程序的.cpp源代码文件中如下:
#include "..\lib.h"
#pragma comment(lib,"..\\debug\\libTest.lib")
//指定与静态库一起链接
  1. .lib中的指令将全部被直接包含在最终生成的 EXE 文件中
    实际代码书写过程中VS按照4里法1配置好就行。只有动态链接库是运行时加载,所以在代码里需要用各种函数找函数地址才能调用!详见2.2部分介绍。

为静态链接库是将全部指令都包含入调用程序生成的EXE文件中。因此如果用的是静态链接库,那么也就不存在“导出某个函数提供给用户使用”的情况,要想用就得全要 ,要不就都别要!

2.2 链接动态库

动态链接库的使用需要库的开发者提供生成的.lib文件和.dll文件。或者只提供dll文件。
首先我们必须先注意到DLL内的函数分为两种:
(1)DLL 导出函数,可供应用程序调用;
(2)DLL 内部函数,只能在 DLL 程序使用,应用程序无法调用它们。
因此调用程序若想调用DLL中的某个函数就要以某种形式或方式指明它到底想调用哪一个函数。

动态调用/显式调用
  • 需要的文件: 动态链接库的dll文件
  • 不需要.h头文件和.lib文件,因为LoadLibrary之后可以使用getProcAddress来查找一个函数的地址从而调用该函数 (显式调用的前提是使用者需要知道想调用的函数的名字、参数、返回值信息,也就是说虽然编译链接用不上.h头文件,但是调用者编程时可能还是要看.h文件作参考来知道函数名字、参数、返回值信息)

显式调用动态库步骤:

1、创建一个函数指针,其指针数据类型要与调用的 DLL 引出函数相吻合。

2、通过 Win32 API 函数LoadLibrary()显式的调用DLL,此函数返回 DLL 的实例句柄。
3、通过 Win32 API 函数GetProcAddress()获取要调用的DLL 的函数地 址,把结果赋给自定义函数的指针类型。
4、使用函数指针来调用 DLL函数。
5、最后调用完成后,通过 Win32 API 函数FreeLibrary()释放DLL 函数。

取得需要的DLL模块------>返回模块句柄
LoadLibrary("DLL模块路径")
取得需要的函数地址———>返回函数指针GetProcAddress(模块句柄,"函数名")
从内存中卸载DLL模块———>FreeLibrary(模块句柄)

其中,函数指针用法可参考博客

静态调用/隐式调用
  • 需要的文件: 头文件 .h 、动态链接库的.lib文件,动态链接库的dll文件
  • 头文件.h和静态链接库使用时的作用一样,使用动态链接库中的函数的项目需要引用该文件才能编译通过
  • .lib包含了函数所在的DLL文件和文件中函数位置的信息,.dll包含了实际执行代码、符号表等等
  • 加载lib的方法:lib是编译链接是用的,跟使用静态链接库时一样有两种方法:

法1.使用编译链接参数或者VS的配置属性来设置
法2.使用pragma编译语句,例如pragma comment(lib,“a.lib”)

#include.........
告诉编译器与 DLL 相对应的.lib 文件所在的路径及文件名
#pragma comment(lib,"路径和文件名")
extern "C" 函数返回类型 _declspec(dllimport) 函数名(参数表)分号
int main()
{
..............
}
  • 加载dll的方法:

dll是运行时用的,链接了lib之后形成的EXE可执行文件中已经有了dll的信息,所以只要把dll放在和exe同一个目录下就可以了,运行时根据EXE需要自动加载dll中的函数

代码示例
方法一:dll的静态加载--将整个dll文件 加载到 .exe文件中;
特点:程序较大,占用内存较大,但速度较快(免去调用函数LOAD LIB等)
测试:
需要文件:  . lib  和 .dll两个文件 (. lib 做 引导用).h文件
示例程序:
#include <stdio.h>
#include <Windows.h>
#include "betabinlib.h"
#pragma comment(lib, "newdll.lib")
 
int main()
{
    printf("2 + 3 = %d \n", add(2, 3));
    return 0;
}

方法二:dll的动态加载--根据需要加载响应函数,随时可卸载。不会因为找不到dll, 导致程序不能运行(需要自己做判断处理)。
只需要 .lib文件,不需要 .h文件。
#include <stdio.h>
#include <Windows.h>
 
int main()
{
    HINSTANCE h=LoadLibraryA("newdll.dll");
    typedef int (* FunPtr)(int a,int b); //定义函数指针 类型 FunPtr
 
    if(h == NULL)
    {
     FreeLibrary(h);	//勿忘释放函数指针
     printf("load lib error\n");
    }
    else
    {
        FunPtr funPtr = (FunPtr)GetProcAddress(h,"add"); //初始化一个该类型的函数指针
        if(funPtr != NULL)
        {
            int result = funPtr(3, 3);	//直接调用该函数
            printf("3 + 3 = %d \n", result);
        }
        else
        {
            printf("get process error\n");
            printf("%d",GetLastError());
        }
        FreeLibrary(h);	//	释放函数指针
    }
 
    return 0;
}

三、总结

  • 静态链接库是.lib格式的文件,一般在工程的设置界面加入工程中,程序编译时会把lib文件的代码加入你的程序中因此会增加代码大小,你的程序一运行lib代码强制被装入你程序的运行空间,不能手动移除lib代码。

  • 动态链接库是程序运行时动态装入内存的模块,格式*.dll,在程序运行时可以随意加载和移除,节省内存空间。

  • 在大型的软件项目中一般要实现很多功能,如果把所有单独的功能写成一个个lib文件的话,程序运行的时候要占用很大的内存空间,导致运行缓慢;但是如果将功能写成dll文件,就可以在用到该功能的时候调用功能对应的dll文件,不用这个功能时将dll文件移除内存,这样可以节省内存空间。

  • 动态链接库:在运行时加载

  • 静态链接库:在编译时直接联到可执行文件中

四、注意

在编写算法组件时,如果给业务集成人员提供 公共头文件 和 动态算法库:

  1. 代码组件在linux下编译,提供 ,so,则在public头文件中的对外 函数声明上,无需加 关键字去修饰,因为linux下的动态库接口全是对外开放的;
  2. 代码组件在windows下编译,提供 .dll, 则要在public头文件中的 函数声明上,加上EXPORT关键字,表明该接口是对外可被调用的;
    //Dll导出支持
    #define EXPORT __declspec(dllexport)
    

.dll和.so的区别

.so文件没有入口函数的概念。而dll却有,虽然不是必须。
.so会导出所有在头文件中定义的符号。而dll却需要使用特殊关键字指名应该导出那些。
.so文件是elf格式的,可以不连接某些静态库,而等应用程序去连接。而dll需要连接静态库。

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C++中的静态链接库动态链接库的生成方法略有不同。下面分别介绍: 1. 静态链接库(Static Library) 静态链接库是指在编译链接阶段将库的代码复制到可执行文件中,因此可执行文件不再依赖于库文件,可以单独运行。静态链接库的生成方法如下: - 编写库的源代码,生成库的目标文件(.o)。 - 将所有目标文件打包成静态链接库文件(.a)。 具体的步骤如下: 首先编译库的源代码,生成目标文件(.o): ``` g++ -c lib.cpp -o lib.o ``` 然后将目标文件打包成静态链接库文件(.a): ``` ar rcs lib.a lib.o ``` 其中,`ar`命令用于打包目标文件,`rcs`参数表示创建库文件并插入目标文件,`lib.a`为库文件名,`lib.o`为目标文件名。 2. 动态链接库(Dynamic Library) 动态链接库是指在程序运行时加载库文件,因此可执行文件依赖于库文件,需要和库文件一起运行。动态链接库的生成方法如下: - 编写库的源代码,生成库的目标文件(.o)。 - 将所有目标文件编译为共享对象文件(.so)。 具体的步骤如下: 首先编译库的源代码,生成目标文件(.o): ``` g++ -c -fPIC lib.cpp -o lib.o ``` 其中,`-fPIC`参数表示生成位置无关代码,是动态链接库的必备参数。 然后将目标文件编译为共享对象文件(.so): ``` g++ -shared -o lib.so lib.o ``` 其中,`-shared`参数表示生成共享对象文件,`lib.so`为共享对象文件名,`lib.o`为目标文件名。 以上就是C++中生成静态链接库动态链接库的方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值