【Linux探索学习】第二十五弹——动静态库:Linux 中静态库与动态库的详细解析

Linux学习笔记:

https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482

前言:

在 Linux 系统中,静态库和动态库是开发中常见的两种库文件类型。它们在编译、链接、内存管理以及程序的性能和可维护性方面有着显著的差异。了解静态库与动态库的区别和使用方式,有助于开发者根据实际需求选择最适合的解决方案。本文将详细介绍静态库与动态库的概念、差异、使用方法,并通过实际的代码示例讲解如何创建和使用这些库。

目录

1. 静态库与动态库的基本概念

静态库(Static Library)

动态库(Dynamic Library)

2. 静态库与动态库的区别

编译与链接时机

文件格式与大小

性能与内存管理

使用场景

3. 如何在 Linux 中创建静态库

创建静态库的步骤

静态库的优缺点

4. 如何在 Linux 中创建动态库

创建动态库的步骤

动态库的优缺点

5. 静态库与动态库的优缺点比较

6. 动态库的加载与链接机制

编译时动态链接

运行时动态链接

7. 静态库与动态库的底层实现

8. 进阶话题

如何处理库版本

库文件的符号表与重定位

库的跨平台使用

结论


1. 静态库与动态库的基本概念

静态库(Static Library)

静态库是一种在编译时就将代码和资源打包到可执行文件中的库。静态库通常是由多个目标文件(.o 文件)组成的,最终在编译时会将这些目标文件的代码合并到程序的可执行文件中。静态库的扩展名通常为 .a

静态库的特点

  • 在编译时将库文件的代码直接嵌入到可执行文件中。
  • 每个程序都需要自己链接一份静态库的副本。
  • 不需要在程序运行时进行额外的文件查找或加载。
  • 编译过程中会把库的所有代码复制到目标文件中,增加了可执行文件的体积。
动态库(Dynamic Library)

动态库是一种在程序运行时加载的共享库。与静态库不同,动态库的代码不会在编译时直接嵌入到可执行文件中,而是在程序运行时通过动态链接器加载。动态库通常具有 .so(Shared Object)扩展名。

动态库的特点

  • 在程序运行时由操作系统动态加载。
  • 可以被多个程序共享,减少了内存和磁盘空间的消耗。
  • 不需要在编译时复制代码,程序的大小较小。
  • 在程序运行时,可以更新动态库,而不需要重新编译所有依赖该库的程序。

2. 静态库与动态库的区别

特性静态库(Static Library)动态库(Dynamic Library)
文件扩展名.a.so
编译时机在编译时静态链接在运行时动态加载
链接方式静态链接(编译时)动态链接(运行时)
程序体积较大,库的代码嵌入程序中较小,库的代码不嵌入程序中
内存管理每个程序都拥有库的副本多个程序共享库的副本
依赖管理依赖是固定的,程序与库紧耦合依赖管理灵活,库的更新不需要重新编译
更新更新需要重新编译所有依赖的程序只需更新动态库,不需要重新编译程序
使用场景不需要动态链接支持的独立应用需要共享库、多程序共享资源的场景
编译与链接时机
  • 静态库的链接发生在编译时。编译器会将库文件的所有目标文件内容复制到程序中,生成一个包含所有必要代码的可执行文件。
  • 动态库的链接发生在程序运行时。动态链接器会在程序启动时加载所需的共享库,并将其中的符号解析并链接到程序中。
文件格式与大小
  • 静态库通常是 .a 格式,文件较大,因为它包含了库中所有的目标文件(.o 文件)。
  • 动态库通常是 .so 格式,文件较小,多个程序可以共享同一个动态库。
性能与内存管理
  • 静态库的程序在运行时不需要加载额外的库文件,因为它们已经嵌入到可执行文件中,程序启动时性能较好。
  • 动态库的程序在运行时需要加载外部库文件,虽然加载过程可能略有延迟,但多个程序可以共享同一个动态库,节省内存和磁盘空间。
使用场景
  • 静态库适合小型应用程序和嵌入式系统,特别是当程序不依赖于大量外部库时。
  • 动态库适合大型系统或需要频繁更新的应用程序,因为库更新不需要重新编译应用程序。

3. 如何在 Linux 中创建静态库

创建静态库的步骤
  1. 编写源代码: 创建一个简单的 C 文件,定义一些函数:

    // mathlib.c
    #include <stdio.h>
    
    int add(int a, int b) {
        return a + b;
    }
    
    int subtract(int a, int b) {
        return a - b;
    }
    
  2. 编译为目标文件: 使用 gcc 将 C 文件编译为目标文件:

    gcc -c mathlib.c -o mathlib.o
    
  3. 创建静态库: 使用 ar 工具将目标文件打包成静态库:

    ar rcs libmath.a mathlib.o
    
  4. 使用静态库: 创建一个程序来调用这个静态库:

    // main.c
    #include <stdio.h>
    
    int add(int, int);
    int subtract(int, int);
    
    int main() {
        printf("Sum: %d\n", add(5, 3));
        printf("Difference: %d\n", subtract(5, 3));
        return 0;
    }
    

    编译并链接静态库:

    gcc main.c -L. -lmath -o main
    
  5. 运行程序

    ./main
    
静态库的优缺点

优点

  • 不需要依赖外部库,程序独立性强。
  • 程序启动速度较快。

缺点

  • 程序文件较大,内存占用较高。
  • 如果库有更新,所有依赖该库的程序都需要重新编译。

4. 如何在 Linux 中创建动态库

创建动态库的步骤
  1. 编写源代码

    // mathlib.c
    #include <stdio.h>
    
    __attribute__((visibility("default"))) int add(int a, int b) {
        return a + b;
    }
    
    __attribute__((visibility("default"))) int subtract(int a, int b) {
        return a - b;
    }
    
  2. 编译为共享库: 使用 gcc 将代码编译为动态库:

    gcc -fPIC -shared mathlib.c -o libmath.so
    
  3. 使用动态库: 创建一个主程序,调用动态库中的函数:

    // main.c
    #include <stdio.h>
    
    int add(int, int);
    int subtract(int, int);
    
    int main() {
        printf("Sum: %d\n", add(5, 3));
        printf("Difference: %d\n", subtract(5, 3));
        return 0;
    }
    

    编译并链接动态库:

    gcc main.c -L. -lmath -o main
    
  4. 设置动态库路径并运行程序

    export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
    ./main
    
动态库的优缺点

优点

  • 可以在程序运行时加载,多个程序共享同一个库。
  • 更新库时无需重新编译依赖程序,降低了维护成本。

缺点

  • 程序启动时需要加载外部库,可能会稍慢。
  • 如果程序依赖的库丢失或版本不兼容,可能会导致运行时错误。

5. 静态库与动态库的优缺点比较

特性静态库动态库
程序大小较大,库的代码嵌入到程序中较小,多个程序共享同一份库
内存使用每个程序都需要加载一份库的副本多个程序共享同一份库,节省内存
启动速度较快,不需要加载外部库文件稍慢,需要加载外部库文件
依赖管理静态,程序与库紧密耦合动态,程序可以独立于库更新
更新需要重新编译所有依赖的程序只需更新库文件,无需重新编译程序

6. 动态库的加载与链接机制

动态库的加载和链接分为两种方式:编译时动态链接(Compile-time Linking)和运行时动态链接(Runtime Linking)。

编译时动态链接

编译时动态链接指的是在编译时指定使用的动态库,编译器会将库的符号信息嵌入到可执行文件中。程序运行时,操作系统会加载对应的动态库。

运行时动态链接

运行时动态链接是指程序通过 dlopen() 等系统调用在运行时加载库文件。这种方式更为灵活,可以根据需要加载不同的库。

7. 静态库与动态库的底层实现

  • 静态库:静态库文件实际上是一个归档文件,里面包含了一些目标文件(.o 文件)。当程序需要使用静态库时,链接器会从静态库中提取所需的目标文件,并将它们嵌入到可执行文件中。
  • 动态库:动态库文件是一个共享对象,包含了可以在多个程序中共享的代码。操作系统通过动态链接器(如 Linux 上的 ld.so)负责加载动态库并解析符号。

8. 进阶话题

如何处理库版本

库的版本管理对于动态库尤为重要。常见的方法是使用符号链接或者版本控制机制来管理不同版本的动态库。

库文件的符号表与重定位

库文件中的符号表包含了函数和变量的符号信息。链接器会根据符号表进行符号解析和重定位。

库的跨平台使用

动态库的跨平台使用通常依赖于编译时指定的架构和平台。使用如 autoconfCMake 等工具可以帮助开发者更好地进行跨平台构建。


结论

静态库与动态库在 Linux 系统中的应用各有优势与劣势。静态库适用于需要独立性较强的程序,而动态库则适用于内存共享和版本更新更加灵活的场景。在实际开发中,开发者应根据应用的需求、维护成本和性能要求来选择合适的库类型。

本篇笔记:


感谢各位大佬观看,创作不易,还请各位大佬点赞支持!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/954085.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Rust自学】12.4. 重构 Pt.2:错误处理

12.4.0. 写在正文之前 第12章要做一个实例的项目——一个命令行程序。这个程序是一个grep(Global Regular Expression Print)&#xff0c;是一个全局正则搜索和输出的工具。它的功能是在指定的文件中搜索出指定的文字。 这个项目分为这么几步&#xff1a; 接收命令行参数读取…

算法-贪心算法简单介绍

下面是贪心算法视频课的导学内容. 目录 1. 什么是贪心算法?2. 贪心算法简单的三个例子:1. 找零问题2. 最小路径和问题3. 背包问题 3. 贪心算法的特点4. 贪心算法学习的方式? 1. 什么是贪心算法? 简单来说, 我们称以局部最优进而使得全局最优的一种思想实现出来的算法为贪心…

Node.js - Express框架

1. 介绍 Express 是一个基于 Node.js 的 Web 应用程序框架&#xff0c;主要用于快速、简便地构建 Web 应用程序 和 API。它是目前最流行的 Node.js Web 框架之一&#xff0c;具有轻量级、灵活和功能丰富的特点。 核心概念包括路由&#xff0c;中间件&#xff0c;请求与响应&a…

day08_Kafka

文章目录 day08_Kafka课程笔记一、今日课程内容一、消息队列&#xff08;了解&#xff09;**为什么消息队列就像是“数据的快递员”&#xff1f;****实际意义**1、产生背景2、消息队列介绍2.1 常见的消息队列产品2.2 应用场景2.3 消息队列中两种消息模型 二、Kafka的基本介绍1、…

459. 重复的子字符串【力扣】——kmp拼接字符串解法

常规kmp解答 class Solution { public:void getNext(int *next,string s){int j0;next[0]0;for(int i1;i<s.size();i){while(j>0 && s[i]!s[j]){jnext[j-1];}if(s[i]s[j]) j;next[i]j;}}bool repeatedSubstringPattern(string s) {if(s.size()0) return false;i…

浅谈云计算06 | 云管理系统架构

云管理系统架构 一、云管理系统架构&#xff08;一&#xff09;远程管理系统&#xff08;二&#xff09;资源管理系统&#xff08;三&#xff09;SLA 管理系统&#xff08;四&#xff09;计费管理系统 二、安全与可靠性保障&#xff08;一&#xff09;数据安全防线&#xff08;…

【STM32】HAL库USB实现软件升级DFU的功能操作及配置

【STM32】HAL库USB实现软件升级DFU的功能操作及配置 文章目录 DFUHAL库的DFU配置修改代码添加条件判断和跳转代码段DFU烧录附录&#xff1a;Cortex-M架构的SysTick系统定时器精准延时和MCU位带操作SysTick系统定时器精准延时延时函数阻塞延时非阻塞延时 位带操作位带代码位带宏…

PHP答题考试系统

&#x1f50d; 这是一款由PHP与Uniapp强强联手打造的小程序答题考试系统&#xff0c;它如同智慧教育领域中的一颗璀璨明珠&#xff0c;凭借其强大的功能和灵活多变的应用&#xff0c;牢牢吸引了无数求知者的目光。系统全面覆盖了多种试题类型&#xff0c;从基础易懂的判断题、单…

瑞芯微 RK 系列 RK3588 使用 ffmpeg-rockchip 实现 MPP 视频硬件编解码-代码版

前言 在上一篇文章中&#xff0c;我们讲解了如何使用 ffmpeg-rockchip 通过命令来实现 MPP 视频硬件编解码和 RGA 硬件图形加速&#xff0c;在这篇文章&#xff0c;我将讲解如何使用 ffmpeg-rockchip 用户空间库&#xff08;代码&#xff09;实现 MPP 硬件编解码。 本文不仅适…

Element Plus 之 el-table相同行合并(通用函数),相同列合并(自行判断需合并的字段以及相应的列下标)

展示 代码 <el-table :data"tableData" border style"width: 100%" :span-method"objectSpanMethod"><el-table-column prop"date" label"Date" width"180" align"center" /><el-table…

深入理解计算机系统阅读笔记-第十二章

第12章 网络编程 12.1 客户端-服务器编程模型 每个网络应用都是基于客户端-服务器模型的。根据这个模型&#xff0c;一个应用时由一个服务器进程和一个或者多个客户端进程组成。服务器管理某种资源&#xff0c;并且通过操作这种资源来为它的客户端提供某种服务。例如&#xf…

ubuntu20.04安装MySQL5.7

deb安装 下载deb文件并配置 wget https://repo.mysql.com//mysql-apt-config_0.8.12-1_all.deb sudo dpkg -i mysql-apt-config_0.8.12-1_all.deb我使用xshell可以正常。 这个弹出框里&#xff0c;选择的是“ubuntu bionic”。(在终端工具上&#xff0c;有可能显示不了选项)【…

CSS | CSS实现两栏布局(左边定宽 右边自适应,左右成比自适应)

目录 一、左边定宽 右边自适应 1.浮动 2.利用浮动margin 3.定位margin 4.flex布局 5.table 布局 二、左右成比自适应 1:1 1flex布局 table布局 1:2 flex布局 三列布局链接&#xff1a;CSS | 实现三列布局&#xff08;两边边定宽 中间自适应&#xff0c;自适应成比&#xff09;-…

Win10微调大语言模型ChatGLM2-6B

在《Win10本地部署大语言模型ChatGLM2-6B-CSDN博客》基础上进行&#xff0c;官方文档在这里&#xff0c;参考了这篇文章 首先确保ChatGLM2-6B下的有ptuning AdvertiseGen下载地址1&#xff0c;地址2&#xff0c;文件中数据留几行 模型文件下载地址 &#xff08;注意&#xff1…

Java中异常的学习

目录 Java 异常概述 异常的抛出机制 异常的解决方法(处理机制) Java异常体系结构 常见的异常 异常处理 try catch finally throws throw 运行期异常和编译期异常 自定义异常 Java 异常概述 在使用计算机语言进行项目开发的过程中&#xff0c;即使程序员把代码写得尽…

python 连接高斯数据库报错

问题1&#xff1a;报错信息&#xff1a; import psycopg2时报错 /lib64/libgssapi_krib5.so.2 symbol krb5_ser_contect_init version krb5_3_MIT not defined in file libkrb5.so.3 错误原因&#xff1a; 解决&#xff1a; 若通过更换krb相关安装包&#xff0c;psycopg2 …

excel 整理表格,分割一列变成多列数据

数据准备 对于很多系统页面的数据是没有办法下载的。 这里用表格数据来举例。随便做数据的准备。想要看excel部分的可以把这里跳过&#xff0c;从数据准备完成开始看。 需要一点前端基础知识&#xff0c;但不多&#xff08;不会也行&#xff09;。 把鼠标放在你想要拿到本地的…

刀客doc:快手的商业化架构为什么又调了?

一、 1月10日&#xff0c;快手商业化及电商事业部进行新一轮的架构调整。作为2025年快手的第一次大调整&#xff0c;变动最大的是负责广告业务的商业化事业部。快手商业化将原来的8个业务中心&#xff0c;现在统合成了5个&#xff0c;行业归拢看上去更加明晰了。 根据自媒体《…

thinkphp 5.0 结合redis 做延迟队列,队列无法被消费

目录 一、Linux 环境下 二、如何验证消息队列被正确监听 一、Linux 环境下 项目部署在Linux 环境下&#xff0c;首先找到项目的部署路径&#xff0c;接着输入命令,这个命令是以守护进程方式进行监听你的队列&#xff0c;只要redis 不关闭 就可以一直监听这个队列 nohup php …

计算机网络 (40)域名系统DNS

前言 计算机网络域名系统DNS&#xff08;Domain Name System&#xff09;是互联网的基础技术之一&#xff0c;它负责将人类可读的域名转换为计算机用来通信的数字IP地址。 一、基本概念 DNS的主要目的是将域名解析或翻译为IP地址&#xff0c;使得用户可以通过简单易记的域名来访…