当前位置:网站首页 > 编程语言 > 正文

动态库和静态库的使用(动态库和静态库的使用区别)



库是写好的,现有的,成熟的,可以复用的代码。本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。所谓静态、动态是指链接。

库文件是事先编译好的方法的合集。

1、静态库的扩展名一般为“.a”或“.lib”;动态库的扩展名一般为“.so”或“.dll”。

2、静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行;动态库在编译时不会放到连接的目标程序中,即可执行文件无法单独运行。

静态库和动态库最本质的区别就是:该库是否被编译进目标(程序)内部。

静态(函数)库
一般扩展名为(.a或.lib),这类的函数库通常扩展名为libxxx.a或xxx.lib 。

这类库在编译的时候会直接整合到目标程序中,所以利用静态函数库编译成的文件会比较大,这类函数库最大的优点就是编译成功的可执行文件可以独立运行,而不再需要向外部要求读取函数库的内容;但是从升级难易度来看明显没有优势,如果函数库更新,需要重新编译。

动态(函数)库
动态函数库的扩展名一般为(.so或.dll),这类函数库通常名为libxxx.so或xxx.dll 。

与静态函数库被整个捕捉到程序中不同,动态函数库在编译的时候,在程序里只有一个“指向”的位置而已,也就是说当可执行文件需要使用到函数库的机制时,程序才会去读取函数库来使用;也就是说可执行文件无法单独运行。这样从产品功能升级角度方便升级,只要替换对应动态库即可,不必重新编译整个可执行文件。

①可实现不同进程间的资源共享
②动态库升级简单,只需要替换库文件,无需重新编译应用程序
③可以控制何时加载动态库,不调用库函数动态库不会被加载                                                       

        所谓库文件,读者可以将其等价为压缩包文件,该文件内部通常包含不止一个目标文件(也就是二进制文件)。

        值得一提的是,库文件中每个目标文件存储的代码,并非完整的程序,而是一个个实用的功能模块。例如,C 语言库文件提供有大量的函数(如 scanf()、printf()、strlen() 等),C++ 库文件不仅提供有使用的函数,还有大量事先设计好的类(如 string 字符串类)。

        库文件的产生,极大的提高了程序员的开发效率,因为很多功能根本不需要从 0 开发,直接调取包含该功能的库文件即可。并且,库文件的调用方法也很简单,以 C 语言中的 printf() 输出函数为例,程序中只需引入 <stdio.h> 头文件,即可调用 printf() 函数。

        调用库文件为什么还要牵扯到头文件呢?首先,头文件和库文件并不是一码事,它们最大的区别在于:

头文件只存储变量、函数或者类等这些功能模块的声明部分;
库文件才负责存储各模块具体的实现部分;
        读者可以这样理解:所有的库文件都提供有相应的头文件作为调用它的接口。也就是说,库文件是无法直接使用的,只能通过头文件间接调用。

头文件和库文件相结合的访问机制,最大的好处在于,有时候我们只想让别人使用自己实现的功能,并不想公开实现功能的源码,就可以将其制作为库文件,这样用户获取到的是二进制文件,而头文件又只包含声明部分,这样就实现了“将源码隐藏起来”的目的,且不会影响用户使用。

        事实上,库文件只是一个统称,代指的是一类压缩包,它们都包含有功能实用的目标文件。要知道,虽然库文件用于程序的链接阶段,但编译器提供有 2 种实现链接的方式,分别称为静态链接方式和动态链接方式,其中

采用静态链接方式实现链接操作的库文件,称为静态链接库;
采用动态链接方式实现链接操作的库文件,称为动态链接库;

在 C、C++ 实际开发过程中,除了可以使用系统库文件外,我们还可以根据实际需要,手动创建静态链接库或者动态链接库。

        静态链接库实现链接操作的方式很简单,即程序文件中哪里用到了库文件中的功能模块,GCC 编译器就会将该模板代码直接复制到程序文件的适当位置,最终生成可执行文件。

使用静态库文件实现程序的链接操作,既有优势也有劣势:

和使用动态链接库生成的可执行文件相比,静态链接库生成的可执行文件的体积更大。

  • 在  发行版系统中,静态链接库文件的后缀名通常用  表示;
  • 在  系统中,静态链接库文件的后缀名为 ;

2.1 创建静态链接库

        静态链接库其实就相当于压缩包,其内部可以包含多个源文件。但需要注意的是,并非任何一个源文件都可以被加工成静态链接库,其至少需要满足以下 2 个条件:

源文件中只提供可以重复使用的代码,例如函数、设计好的类等,不能包含 main 主函数;
        源文件在实现具备模块功能的同时,还要提供访问它的接口,也就是包含各个功能模块声明部分的头文件;

 
  

 代码

 
  

 代码, 其中包含 ,不创建静态库时可以不用包含该头文件。

 
  

 代码,其中包含 ,不创建静态库时可以不用包含该头文件。

 
  

 代码

 
  

        对于name.cpp 和 greeting.cpp 都符合以上两个条件, 因此都可以被加工成静态链接库。并且根据实际需要,我们可以将它们集体压缩到一个静态链接库中,也可以各自压缩成一个静态链接库。

将源文件打包为静态链接库的过程很简单,只需经历以下 2 个步骤:

        1.将所有指定的源文件,都编译成相应的目标文件

 
  

        2.然后使用  压缩指令,将生成的目标文件打包成静态链接库,其基本格式如下:

 
  

        3.有关  打包压缩指令,以及  各选项的含义和功能,请参考 Linux ar命令

重点说明的是,静态链接库的不能随意起名,需遵循如下的命名规则:

 
  
  •  系统下,静态链接库的后缀名为 ;
  •  系统下,静态链接库的后缀名为 ;
  • 其中, 代指我们为该库起的名字,比如  系统自带的一些静态链接库名称为 、、,它们的名称分别为 、 和 。

    下面,将 、 打包到一个静态链接库中:

  • 其中, 就是 、 一起打包生成的静态链接库, 是我们自定义的库名。
     

2.2 使用静态链接库

静态链接库的使用很简单,就是在程序的链接阶段,将静态链接库和其他目标文件一起执行链接操作,从而生成可执行文件。

以前面代码为例,首先我们将  文件编译为目标文件:

 
  

在此基础上,我们可以直接执行如下命令,即可完成链接操作:

 
  

其中, 选项强制  编译器使用静态链接库。

注意,如果  编译器提示无法找到 ,还可以使用如下方式完成链接操作:

 
  

其中,

        -L(大写的 L)选项用于向 GCC 编译器指明静态链接库的存储位置(可以借助 pwd 指令查看具体的存储位置);
        -l(小写的 L)选项用于指明所需静态链接库的名称,注意这里的名称指的是 xxx 部分,且建议将 -l 和 xxx 直接连用(即 -lxxx),中间不需有空格。

由此,就生成了 a.out 可执行文件:

 
  

        动态链接库,又称为共享链接库。和静态链接库不同,采用动态链接库实现链接操作时,程序文件中哪里需要库文件的功能模块,GCC 编译器不会直接将该功能模块的代码拷贝到文件中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件。

        显然,这样生成的可执行文件是无法独立运行的。采用动态链接库生成的可执行文件运行时,GCC 编译器会将对应的动态链接库一同加载在内存中,由于可执行文件中事先记录了所需功能模块的位置信息,所以在现有动态链接库的支持下,也可以成功运行。

采用动态链接库实现程序的连接操作,其优势和劣势恰好和静态链接库相反:

  • 优势是,由于可执行文件中记录的是功能模块的地址,真正的实现代码会在程序运行时被载入内存,这意味着,即便功能模块被调用多次,使用的都是同一份实现代码(这也是将动态链接库称为共享链接库的原因)。
  • 劣势是,此方式生成的可执行文件无法独立运行,必须借助相应的库文件(可移植性差)。

和使用静态链接库生成的可执行文件相比,动态链接库生成的可执行文件的体积更小,因为其内部不会被复制一堆冗余的代码。

在 Linux 发行版系统中,动态链接库的后缀名通常用 .so 表示;
在 Windows 系统中,动态链接库的后缀名为 .dll;

        GCC 编译器生成可执行文件时,默认情况下会优先使用动态链接库实现链接操作,除非当前系统环境中没有程序文件所需要的动态链接库,GCC 编译器才会选择相应的静态链接库。如果两种都没有(或者 GCC 编译器未找到),则链接失败。

3.1 创建动态链接库

总的来说,动态链接库的创建方式有 2 种。

  1. 直接使用源文件创建动态链接库,采用  命令实现的基本格式如下:
 
  

其中,

        -shared 选项用于生成动态链接库;
        -fpic(还可写成 -fPIC)选项的功能是,令 GCC 编译器生成动态链接库(多个目标文件的压缩包)时,表示各目标文件中函数、类等功能模块的地址使用相对地址,而非绝对地址。这样,无论将来链接库被加载到内存的什么位置,都可以正常使用。

例如,将前面项目中的 greeting.cpp 、name.cpp 这 2 个源文件生成一个动态链接库,执行命令为:

 
  

注意,动态链接库的命名规则和静态链接库完全相同,只不过在 Linux 发行版系统中,其后缀名用 .so 表示;Windows 系统中,后缀名为 .dll。

 
  

在此基础上,接下来利用上一步生成的目标文件,生成动态链接库:

 
  

3.2 使用动态链接库

        通过前面章节的学习我们知道,动态链接库的使用场景就是和项目中其它源文件或目标文件一起参与链接。以前面例子为例,前面我们将 greeting.cpp、name.cpp 打包到了 libmyfunction.so 动态链接库中,此时该项目中仅剩 main.cpp 源程序文件,因此执行 demo 项目也就演变成了将 main.cpp 和 libmyfunction.so 进行链接,进而生成可执行文件。

注意,function.h 头文件并不直接参与编译,因为在程序的预处理阶段,已经对项目中需要用到的头文件做了处理。

执行如下指令,即可借助动态链接库成功生成可执行文件:

 
  

注意,生成的可执行文件  通常无法直接执行,例如:

 
  

可以看到,执行过程中无法找到  动态链接库。通过执行  指令,可以查看当前文件在执行时需要用到的所有动态链接库,以及各个库文件的存储位置:

 
  

        可以看到,main 文件的执行需要 7 个动态链接库的支持,其中就包括 libmyfunction.so,但该文件无法找到,因此 main 执行会失败。

        运行由动态链接库生成的可执行文件时,必须确保程序在运行时可以找到这个动态链接库。常用的解决方案有如下几种:

 
  

其中  为动态链接库文件的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效);

  • 修改  或  文件,即在文件最后一行添加
 
  

其中  为动态链接库文件的绝对存储路径,保存之后,执行  指令(此方式仅对当前登陆用户有效)。

在本示例中采用第二种方案,即在终端输入

 
  

即可使  成功执行。

 
  

到此这篇动态库和静态库的使用(动态库和静态库的使用区别)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • 电池mha是什么意思(电池ml什么意思)2025-08-25 08:54:04
  • 字符转码方法(字符转码方法有几种)2025-08-25 08:54:04
  • 位置定位怎么更改位置信息(如何改定位位置信息)2025-08-25 08:54:04
  • 怎么改变数组的值(怎么改变数组的值大小)2025-08-25 08:54:04
  • libxml2源码(libxml2-devel 源码安装)2025-08-25 08:54:04
  • 在线16进制转换工具(在线16进制转换工具下载)2025-08-25 08:54:04
  • m301h(m301H卡刷固件)2025-08-25 08:54:04
  • libglesv2.dll丢失(libpng15.dll丢失)2025-08-25 08:54:04
  • ipv6单播地址有(ipv6全球单播地址网关)2025-08-25 08:54:04
  • 二级域名解析网站(域名解析二级域名)2025-08-25 08:54:04
  • 全屏图片