【一分钟学C++】动态库与静态库

在这里插入图片描述

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~
公众号: C++学习与探索  |  个人主页: rainInSunny  |  个人专栏: Learn OpenGL In Qt

动态库

常见格式

  动态库是一种常见的库文件形式,主要包含以下几种格式:

  • windows:.dll
  • linux:.so
  • mac:.dylib/.framework

特点

  动态库有以下特点:

  • 运行时加载:
    动态库在程序运行时被加载到内存中,这意味着可执行文件本身不包含动态库的代码,只是符号表中引用了动态库中的接口。但是这也带来了运行环境的问题,如果当前可执行程序运行动态库环境缺失或者版本不匹配,都会导致程序运行异常。
  • 共享性:
    多个应用程序可以同时使用同一个动态库,从而节省了磁盘空间和内存。这种共享性使得动态库成为一种高效的资源利用方式。
  • 易于更新和维护
    由于动态库的代码没有被直接编译到可执行文件中,因此可以独立于应用程序进行更新,这大大简化了库的维护和版本控制。在动态库中的修改满足二进制兼容的情况下,只需要重新编译更新动态库部分,其它部分无需改动就可以完成更新。
  • 版本灵活性:
    系统可以同时存在多个版本的动态库,这为开发者提供了更大的灵活性,开发者可以手动通过 dlopen 等方式显示加载需要版本的动态库。
  • 可能影响程序启动性能:
    由于动态库需要在运行时加载,这可能会增加程序的启动时间。

加载方式

在这里插入图片描述
  当我们在 CMakLists 中添加图中所示的指令后,就实现了对 qecomponents 目标链接 Qt5::Widgets 等动态库。使用这种链接方式,当 qecomponents 被加载到内存中时,其链接的动态库也都会被加载到内存中。这样的好处是这些动态库中导出的符号对外都可以正常使用了,但是如果依赖过于复杂,会导致应用程序启动过程需要加载过多的动态库,可能有些插件类型的动态库在整个应用程序的生命周期内都不会被使用,这样就很浪费资源,同时也会让启动速度变慢。
在这里插入图片描述
  上图展示了 unix 环境 dlopen 函数的说明,该函数提供了一种手动显示加载动态库的方式。这样带来的好处是可以按需加载动态库,插件类的动态库可以在被使用的时候进行加载,避免资源浪费。

静态库

常见格式

  静态库主要包含以下几种格式:

  • windows:.lib
  • linux:.a
  • mac:.a

特点

  静态库有以下特点:

  • 运行时无关性:
    由于静态库在编译时已经被完全拷贝到链接到它的可执行程序或者动态中,因此程序在运行时与静态库再无瓜葛。这使得程序的移植变得方便,因为不需要担心运行时环境中是否存在所需的库文件。
  • 无加载耗时:
    因为静态库本身被包含在可执行程序中,程序运行时不需要单独加载,不会产生额外耗时。
  • 增大程序体积:
    如果存在多个库链接同一个静态库,可能导致静态库中的符号被重复包含,造成程序体积增大。

动态库和静态库中的符号导出

  作为一个库文件,一般都会提供一些导出符号供外部使用。图中给出了 Q_DECL_EXPORT 和 Q_DECL_IMPORT 在 windows 和 linux 上的实现,通过添加这样的前缀,可以在动态库和静态库中实现函数符号的导出。
在这里插入图片描述
  在 windows 上默认是不会导出函数符号的,一般需要手动添加导出前缀,在 linux 上,一些编译器默认开启了函数符号导出,如果需要关闭默认的函数符号导出,可以设置 -fvisibility=hidden 编译选项来实现。

常见问题

  • 静态库中的所有符号都会被链接的可执行文件或动态库包含吗?
    答:不会,就 C++11 标准来说,最小的编译单元是一个独立的 cpp 文件,如果使用到其中的符号,那么这个 cpp 中其它符号也会被包含,没有任何被使用函数的 cpp 文件中的函数符号不会被包含。另外如果需要包含静态库中所有的函数符号,可以添加下面的链接选项。
    在这里插入图片描述

  • 有办法避免静态库中的符号被重复包含吗?
    答:可以通过一个指定动态库来导出静态库中需要导出的符号,首先在静态库中需要导出符号前添加导出前缀,在指定动态库中引用这些符号,并且指定动态库链接静态库,这样其它库可以通过链接指定动态库来实现对静态库中导出符号的访问,由于都通过指定动态库链接,所以不存在重复符号包含。但是要注意的是指定动态库中需要有静态库中导出符号的引用,否者符号可能不会包含在动态库中。

  • 包含全局静态变量和局部静态变量的头文件(例如单例模式的 instance() 函数在头文件中用 static 实现),在不同动态库中引用会有问题吗?
    答:会存在隐患,例如单例期望是全局只有一份实例,但是在头文件中实现,被多个动态库中都引用了,这样会导致不同动态库中各自有一份自己的实例,可能会导致预期之外的行为。

  • 静态库编译过程中使用了其它库的函数符号但是没有链接对应库,单独编译这个静态库时会报错吗?
    答:不会,单独编译一个静态库可以认为不存在链接的过程,只是将编译出来的符号进行打包,只有编译到依赖该静态库的动态库或者可执行文件时,才会报链接错误。

关注公众号:C++学习与探索,有惊喜哦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值