首页 > 编程语言 >【IO编程】静态库 和 动态库

【IO编程】静态库 和 动态库

时间:2025-01-15 11:01:20浏览次数:3  
标签:lib 编译 静态 编程 int IO 动态 加载

在软件开发中, 是一组已编译的代码集合,提供了程序可以直接调用的功能模块(如数学运算、字符串处理、文件操作等)。库的主要作用是提高代码复用性、减少重复开发,并提供标准化功能。

什么是库

库(Library) 是一个包含函数、类或其他可重用代码的集合。开发者在程序中调用库中的函数或功能,避免从零开始编写程序。

根据特定的功能开发的代码模块,供其它应用程序调用。一般来说库本身不提供应用代码。有的是源代码,比如 python 库,网页前端库 vue、jQuery。有的是经过编译的目标代码,比如 C 程序,Java 的 jar 包。C 语言库分为动态库和静态库,在 Windows 系统中动态库以 .dll 为后缀,静态库以 .lib 为后缀;Linux 系统动态库以 .so 为后缀,静态库以 .a 为后缀。

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于windows和linux的本质不同,因此二者库的二进制是不兼容的。

linux下的库有两种:
静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。

C 语言库分为动态库和静态库,在 Windows 系统中动态库以 .dll 为后缀,静态库以 .lib 为后缀;Linux 系统动态库以 .so 为后缀,静态库以 .a 为后缀。

静态库
在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。
动态库
在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入,因此在程序运行
时还需要动态库存在,因此代码体积较小。

库的形式:

  • 源代码库:以源代码形式提供(如 .c.h 文件)。
  • 二进制库:以已编译的二进制形式提供(如 .a.so.dll 等)。

根据链接方式和使用时机,库分为:

  • 静态库(Static Library):在编译时链接到程序中。
  • 动态库(Dynamic Library):运行时动态加载到程序中。

库的意义:

库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。

共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

静态库

1> 静态库的特点

静态库可用于静态编译,编译时需要将静态库合并到可执行程序中,因此会增大可执行程序的大小,但在执行时不需要加载库,直接跳转执行即可。

静态库对函数库的链接是放在编译时期(compile time)完成的,它在程序编译的时候被直接打包进可执行文件。
编译后,静态库与目标文件结合,形成一个独立的可执行程序。
静态库的扩展名:
 * Linux/Unix:.a(archive)
 * Windows:.lib

优点:
	1. 程序在运行时与函数库再无瓜葛,不依赖外部库,移植方便。
	2. 加载速度快:所有依赖已经嵌入可执行文件,运行时不需要动态加载。
缺点:
	1. 文件体积大:每个程序都包含静态库的副本,占用更多存储空间。---> 浪费空间和资源,因为所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。
	2. 更新起来不方便:如果库更新,需要重新编译所有依赖该库的程序。
2> 制作静态库

2.1> 创建静态库的源文件(编写一个简单的 C 函数):

/*n个自然数之和的计算*/

int mysum(int n)
{
    int sum = 0;
    
    /*判断传入的数字是否为自然数*/
    if(n <= 0)
        return -1;
    else
    {
        /*做n个自然数之和的计算保存到sum中*/
        for(int i = 1; i <= n;i++)
        {
            sum += i;
        }
    }
    return sum;
}

2.2> 创建静态库的头文件:

#ifndef __MYSUM_H__ //防止头文件被重复包含
#define __MYSUM_H__

int mysum(int n);

#endif

2.3> 编译生成.o文件:

gcc -c mysum.c -o mysum.o

2.4> 将.o文件制作成静态库 (命名为lib库名.a) / 使用 ar 工具创建静态库:

ar crs libmysum.a mysum.o

# ar的 c参数表示为创建一个档案文件
# 	 r参数表示为将文件添加到所创建的库中
# 	 s参数表示为生成索引以提高库被链接时的效率
3> 测试静态库

3.1> 编写一个测试代码:

#include <stdio.h>
#include "mysum.h"

int main(void)
{
    int n;
    printf("请输入一个正整数:\n");
    scanf("%d",&n);

    printf("自然数%d 的和结果为%d\n",n,mysum(n));

    return 0;
}

3.2> 编译并连接静态库:

gcc test.c -o test -lmysum -L. //-l链接了mysum这个库,-L声明了该库的路径在当前目录

-l库名 --- 表示链接库(诶路)
-L库路径 --- 表示指定链接库的所在路径

3.3> 运行测试代码:

farsight@ubuntu:~/shared/static_lib$ ./test
请输入一个正整数:
10
自然数10 的和结果为55
farsight@ubuntu:~/shared/static_lib$ ./test
请输入一个正整数:
100
自然数100 的和结果为5050

以上。便是静态库的制作 与 在开发中的使用。

动态库

1> 动态库的特点

动态库可用于动态编译,编译时并不会将动态库合并到可执行代码中,而是在可执行代码中创建对动态库的链接。因此使用动态编译的可执行文件就小。动态编译的可执行程序运行时,需要动态加载库到进程中进行调用。

动态库把对一些库函数的链接载入推迟到程序运行的时期(runtime)。 动态库在程序运行时由操作系统动态加载。

可以实现进程之间的资源共享。

将一些程序升级变得简单。

甚至可以真正做到链接载入完全由程序员在程序代码中控制。


动态链接库的名字形式为 “libxxx.so” 后缀名为 “.so”:
	动态库的扩展名:
		 * Linux/Unix:.so(shared object)
		 * Windows:.dll(dynamic link library)

针对于实际库文件,每个共享库都有个特殊的名字“soname”。在程序启动后,程序通过这个名字来告诉动态加载器该载入哪个共享库。

在文件系统中,soname仅是一个链接到实际动态库的链接。

对于动态库而言,每个库实际上都有另一个名字给编译器来用。它是一个指向实际库镜像文件的链接文件。这个时候soname是没有版本号的。

动态库的优点:1.节省存储空间:多个程序可以共享同一个动态库。2.便于更新:更新动态库后,所有依赖的程序自动使用新版本,无需重新编译。
动态库的缺点:1.依赖性:程序运行时需要动态库,缺少库会导致程序无法启动。2.加载时间:程序运行时需要加载动态库,启动速度较静态库慢。
2> 制作动态库

2.1> 创建动态库的源文件:

/*n个自然数之和的计算*/

int mysum(int n)
{
    int sum = 0;
    /*判断传入的数字是否为自然数*/
    if(n <= 0)
        return -1;
    else
    {
        /*做n个自然数之和的计算保存到sum中*/
        for(int i = 1; i <= n;i++)
        {
            sum += i;
        }

    }
    return sum;
}

2.2> 创建动态库的头文件:

#ifndef __MYSUM_H__ //防止头文件被重复包含
#define __MYSUM_H__

int mysum(int n);

#endif

2.3> 编译生成.o文件:

gcc -fPIC -Wall -c mysum.c

# -fPIC:生成位置无关代码(Position-Independent Code)。

2.4> 将.o文件制作动态库(命名为lib库名.so):

gcc -shared -o libmysum.so mysum.o  //shared指定生成动态链接库
3> 测试动态库

3.1> 编写一个测试代码:

#include <stdio.h>
#include "mysum.h"

int main(void)
{
    int n;
    printf("请输入一个正整数:\n");
    scanf("%d",&n);

    printf("自然数%d 的和结果为%d\n",n,mysum(n));

    return 0;
}

3.2> 编译并连接动态库:

gcc test.c -o test -lmysum -L. //-l链接了mysum这个库,-L声明了该库的路径在当前目录

-l库名 --- 表示链接库(诶路)
-L库路径 --- 表示指定链接库的所在路径

3.3> 装载动态库:

farsight@ubuntu:~/shared/dynamic_lib$ ./test
./test: error while loading shared libraries: libmysum.so: cannot open shared object file: No such file or directory
方法一:
将动态库拷贝到系统的库的目录中:	/lib/  或者/usr/lib
sudo cp libmysum.so /lib
方法二:
将库的路径添加到库的配置文件中:

​	打开配置文件:	sudo vim /etc/ld.so.conf.d/my.conf
​    添加路径:			/home/farsight/shared/dynamic_lib (根据自己实际的库的路径来添加)
​    是配置文件生效: sudo ldconfig
方法三:
将库的路径添加到库的环境变量中(只作用于当前终端,关闭后失效)

​	查看环境变量:
​	echo $LD_LIBRARY_PATH

​    添加库路径到环境变量中:
​	export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/farsight/shared/dynamic_lib

3.4> 运行测试代码:

farsight@ubuntu:~/shared/IO/day3/dynamic_lib$ ./test
请输入一个正整数:
10
自然数10 的和结果为55
farsight@ubuntu:~/shared/IO/day3/dynamic_lib$ ./test
请输入一个正整数:
100
自然数100 的和结果为5050

加载库

静态库的加载

静态库在编译阶段直接加载到可执行文件中,在编译时通过链接器(ld)完成库的合并。

动态库的加载

动态库的加载可以分为两种方式:

  1. 自动加载
    • 在程序启动时,操作系统根据程序的依赖自动加载动态库。
    • 依赖库路径可以通过 LD_LIBRARY_PATH 环境变量指定(Linux)。
  2. 手动加载(动态加载)
    • 程序运行时显式加载动态库,使用库中的函数。
    • 在 Linux 中可以使用 dlopen()dlsym()dlclose()
      动态加载
#include <stdio.h>
#include <dlfcn.h>

int main() {
    // 加载动态库
    void *handle = dlopen("./libmath.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "Error: %s\n", dlerror());
        return 1;
    }

    // 获取函数指针
    int (*add)(int, int) = dlsym(handle, "add");
    int (*subtract)(int, int) = dlsym(handle, "subtract");
    if (!add || !subtract) {
        fprintf(stderr, "Error: %s\n", dlerror());
        dlclose(handle);
        return 1;
    }

    // 调用函数
    printf("Add: %d\n", add(3, 2));
    printf("Subtract: %d\n", subtract(3, 2));

    // 关闭动态库
    dlclose(handle);
    return 0;
}

创建和安装共享库

在 Linux 系统中,创建动态库后,可以安装到系统的标准路径中,供所有程序使用 (开发中常用)

1 将动态库复制到标准路径:

  • 复制动态库到 /usr/lib//usr/local/lib/
sudo cp libmath.so /usr/local/lib/
  • 更新动态库缓存:
sudo ldconfig

2 配置动态库路径:

  • 如果动态库不在标准路径中,可以通过设置 LD_LIBRARY_PATH 环境变量指定路径:
export LD_LIBRARY_PATH=路径:$LD_LIBRARY_PATH
  • main.c 中调用动态库时:
./main
二者的区别

静态库

  1. 在编译阶段将库代码直接嵌入到程序中,适合独立运行的程序
  2. 优点:运行时不依赖外部库,加载快。
  3. 缺点:文件体积大,更新麻烦。

动态库

  1. 在运行时由操作系统加载,多个程序可以共享一个动态库
  2. 优点:节省存储空间,易于更新。
  3. 缺点:运行时依赖,启动稍慢。
特性静态库动态库
文件扩展名.a(Linux), .lib.so(Linux), .dll
链接方式编译时链接运行时加载
运行依赖无需额外依赖程序运行时需要动态库
文件大小较大(包含库代码)较小(共享库代码)
更新成本高(需重新编译)低(更新库即可)
加载速度较慢(需动态加载)

额外附加相关的一些 GCC 操作选项:

	-shared:指定生成动态链接库。
	-fPIC:表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,概念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。
	-w1,options:把参数(options)传递给链接器1d。如果options中间有逗号,就将options分成多个选项,然后传递给链接程序。
	-static:指定生成静态链接库。
	-c:只激活预处理、编译和汇编,也就是把程序做成目标文件(.o文件)。
	-E:使用-E选项可以让GCC停止在预处理完成阶段(完成所有#define,#if,#include等替换),输出到标准输出,除非指定-0选项,qcc不再做更多的处理。可使用-0选项生成一个以i结尾的文件(GCC默认将.i文件看成是预处理后的C语言源代码)
	-S:停止在汇编阶段,输出.s(汇编语言源码)但不调用as

最后,在实际开发中,我们对于静态库或动态库的选择取决于应用场景:

  • 静态库适用于单机程序或对性能要求高的场景。
  • 动态库适用于需要共享代码、频繁更新的场景。

以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。

我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!

标签:lib,编译,静态,编程,int,IO,动态,加载
From: https://blog.csdn.net/qq_39725309/article/details/145126788

相关文章

  • vue.js actions和getters
    在Vue.js中,使用vuex状态管理库来管理全局状态。其中,actions和getters是vuex中的两个重要概念。actions用于处理异步操作,例如发送HTTP请求或者其他需要等待结果的操作。它可以包含任意异步操作,并且可以通过commit方法来触发mutations的方法来改变state,也可以通过dispatch方法来......
  • vue.js辅助函数-mapMutations
    在Vue.js中,使用辅助函数可以更方便地使用Vuex的mutation。而mapMutations就是Vuex提供的一个辅助函数,它可以将mutation映射到组件的methods中,使得我们可以在组件中直接调用mutation,而不需要手动进行commit。mapMutations函数接收一个字符串数组或对象作为参数,数组中的字符串即......
  • 【PCL】Segmentation 模块—— 平面模型分割(Plane model segmentation)
    1、简介PCL(PointCloudLibrary)中的平面模型分割(PlaneModelSegmentation)是一种从点云数据中提取平面结构的方法。它通过识别点云中符合平面模型的点集,将场景中的平面区域分割出来。1.1主要步骤选择模型:选择平面模型作为分割目标。采样点:随机选取点云中的点用于模型拟......
  • 【程序猿面试真题——计算机基础知识和编程】如何寻找二次曲线(离散的点连成的)的最小值
    【程序猿面试真题——计算机基础知识和编程】如何寻找二次曲线(离散的点连成的)的最小值?【程序猿面试真题——计算机基础知识和编程】如何寻找二次曲线(离散的点连成的)的最小值?文章目录【程序猿面试真题——计算机基础知识和编程】如何寻找二次曲线(离散的点连成的)的最小......
  • Fc region为何如此重要?
    前 言目前,全球范围内已超过100多种抗体类药物获批上市,肿瘤、自身免疫性疾病、炎症等疾病治疗领域已取得了令人瞩目的进展。抗体在临床治疗、体外诊断、科学研究等领域发挥重要作用。1 抗体结构和作用机制众所周知,抗体的结构呈Y字形,分为两部分区域:Fab臂和Fc尾。Fab臂识别......
  • 解密 Apple Vision Pro 的眼睛舒适度调节技术
    如果你在长时间佩戴使用VisionPro后感觉到异常的眼睛疲劳,即便没有观看太多高速运动的画面仍然感觉到眩晕,或者在摘下VisionPro后眼睛需要额外花一点时间才能重新对焦到周边物体,那么你可以尝试手动调整一下这一显示屏距离,以找到最适合自己的屏幕显示效果。【视频Vision......
  • 【零基础SD教程】2024最细自学Stable Diffusion全套教程!附 Sd 安装包,拿走不谢
    看:哈哈是不是很漂亮?但这些都不是真实存在的直接通过AI生成的美女达到如此逼真的地步是怎么做到的呢?那么接下来就是:学习生成小姐姐的正确姿势首先需要在你的电脑中安装一个「stable-diffusion」接下来就推荐几个大模型,以下均为个人根据SD软件出图的效......
  • 静态分析在分支开发主干发布模式下的应用
    静态分析在分支开发主干发布模式下的应用在采用分支开发主干发布模式的项目中,静态分析可以有效地确保每次合并到主干的代码质量。以下是具体的操作步骤和措施,确保变更请求经过审批,并在审批过程中检查静态分析的结果。1.配置管理工具和静态分析工具的集成目标确保静态分......
  • 【Varnish】:解决 Varnish 7.6 CDN 静态资源缓存失效问题
    项目场景:在一个使用Varnish作为反向代理的Web应用中,我们依赖CDN(内容分发网络)来缓存静态资源(如图片、CSS、JavaScript文件等),以提高全球用户的访问速度并减轻源站服务器的负载。然而,在实际运行中,我们遇到了一个问题:CDN缓存的静态资源全部一直回源,导致源站服务器负载过高,响应时间......
  • 使用Axios实现无刷新信息验证:提升用户体验
    使用Axios实现无刷新信息验证:提升用户体验在现代Web开发中,用户体验至关重要。尤其是在信息验证的场景中,用户通常希望能迅速得到反馈,而不必每次都刷新页面。这篇文章将详细探讨如何使用Axios实现无刷新信息验证,提升用户体验与效率。我们将通过一个具体的例子来展示使用Axios......