C/C++静态库和动态库

C/C++静态库和动态库

目标

  1. 创建与使用静态库、动态库
  2. 静态库和动态库的区别
  3. 使用时如何选择

什么是库?

库是写好的现有的,成熟的,可以复用的代码

库的本质

一种可执行代码的二进制形式,可以被操作系统载入内存执行.

库的种类

  • 静态库(.a.lib)
  • 动态库(.so.dll)

程序编译过程:

如图所示:

image

静态库

本质:

一组目标文件(.o/.obj文件的集合).很多目标文件经过压缩打包后形成的一个文件

特点:

  • 静态库对函数库的链接是放在编译时期完成的
  • 程序在运行时与函数库无瓜葛,移植方便
  • 浪费空间和资源,所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件

创建静态库的过程

image

Windows下创建静态库:

  1. 使用vs命令行生成静态库:
  • 使用带编译器选项/cCl.exe编译代码(cl/c StaticMath.cpp),创建名为StaticMath.obj的目标文件
  • 使用库管理器Lib.exe链接代码(lib StaticMath.obj),创建静态链接库StaticMath.lib
  1. 使用vs工程设置生成静态库:
  • 创建win32控制台程序时,勾选静态库类型;打开工程“属性面板”è”配置属性”è”常规”,配置类型选择静态库

  • 创建的时候选择语言、选择平台、选择库

使用静态库

  1. 添加StaticMath.h头文件目录,打开工程属性面板->属性配置->c/c++->常规

  2. 在附加包含目录属性值中输入StaticMath.h头文件所在目录

  3. 打开工程属性面板->配置属性->链接器->命令行,输入静态库的完整路径

动态库

动态库的存在是为了弥补静态库的不足

静态库的两个缺点:

  • 空间浪费

动态库加载示例:

image

  • 静态库对程序的更新、部署和发布页会带来麻烦。静态库liba.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新

动态库的特点

  • 把对一些库函数的链接载入推迟到程序运行的时期
  • 实现进程之间的资源共享(动态库也称之为共享库)
  • 程序升级变得简单
  • 真正做到链接载入完全由程序员在程序代码中控制->(只显示调用)

动态库加载过程:

image

Windows创建动态库:

  • Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数做出初始化的入口,在导出函数的声明时需要有_declspec(dllexport)关键字

  • Linuxgcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明

使用动态库

  1. 添加DynamicMath.h头文件目录,打开工程属性面板->配置属性->C/C++->常规,在附加包含目录属性值中,键入DynamicMath.h头文件所在目录的路径

  2. 属性面板->配置属性->链接器->常规,附加依赖库目录中输入,动态库所在目录

  3. 属性面板->配置属性->链接器->输入,附加依赖库中输入动态库编译出来的DynamicLibrary.lib

静态库和动态库的Lib文件

静态库对应的lib文件叫静态库,动态库对应的lib文件叫导入库

静态库:

本身就包含了实际执行代码、符号表等等

动态库:

实际的执行代码位于动态库中,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息

动态库的显式调用

Linux下显式调用动态库

#include <dlfcn.h>,提供了下面几个接口:

void * dlopen( const char * pathname, int mode ); // 函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。

void* dlsym(void* handle,const char* symbol); // dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。

int dlclose (void *handle);// dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

const char *dlerror(void);// 当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

Windows下显式调用动态库

应用程序必须进行函数调用以在运行时显式加载DLL

显式链接到DLL,应用程序必须:

  • 调用LoadLibrary(或相似函数),以加载Dll和获取模块句柄
  • 调用GetProcAddress,以获取指向Application要调用的每个导出函数的函数指针,应用程序是通过指针调用DLL的函数,编译器不生成外部引用,故无需与导入库链接
  • 使用完Dll以后调用FreeLibrary

总结

静态库和动态库的区别:

代码被载入的时刻不同--->生成的文件后缀也不同(静态库.a,lib)、(动态库.so,dll)

  • 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大
  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小
posted @   俊king  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示