Linux 动态库和静态库 【详解】

news2025/2/25 15:10:22

动静态库的基本原理

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
  • 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
  • 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间

动静态库的本质是可执行程序的“半成品”。

对于文件变成可执行程序的过程:

  1. 预处理: 完成头文件展开、去注释、宏替换、条件编译等,最终形成xxx.i文件。
  2. 编译: 完成词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,最终形成xxx.s文件。
  3. 汇编: 将汇编指令转换成二进制指令,最终形成xxx.o文件。
  4. 链接: 将生成的各个xxx.o文件进行链接,最终形成可执行程序。

就像这样,test1.c、test2.c、test3.c、以及main.c形成可执行文件,我们需要先得到各个文件的目标文件test1.o、test2.o、test3.o以及main.o,然后再将这写目标文件链接起来,最终形成一个可执行程序。

在这里插入图片描述
而实际上,对于可能频繁用到的源文件,比如这里的test1.c、test2.c、test3.c,我们可以将它们的目标文件test1.o、test2.o、test3.oo进行打包,之后需要用到这四个目标文件时就可以之间链接这个包当中的目标文件了,而这个包实际上就可以称之为一个库。
在这里插入图片描述
实际上,所有库本质都是一堆目标文件(xxx.o)的集合,库的文件当中并不包含主函数而只是包含了大量的方法以供调用,所以说动静态库本质是可执行程序的“半成品”。

认识动静态库

在Linux运行:

#include <stdio.h>

int main()
{
	printf("hello world\n"); //库函数
	return 0;
}

这份代码通过printf输出hello world,是因为gcc编译器在生成可执行程序,将C标准库也链接进来了。

在Linux下,我们可以通过ldd 文件名来查看一个可执行程序所依赖的库文件。
在这里插入图片描述
这里可执行程序所依赖的libc.so.6实际上就是C动态库,当我们去掉一个动静态库的前缀lib,再去掉后缀.so或者.a及其后面的版本号,剩下的就是这个库的名字。

而gcc/g++编译器默认都是动态链接的,若想进行静态链接,可以携带一个-static选项。

动静态库各自的特征

静态库

静态库是程序在编译链接的时候把库的代码复制到可执行文件当中的,生成的可执行程序在运行的时候将不再需要静态库,因此使用静态库生成的可执行程序的大小一般比较大。

优点:

  • 使用静态库生成可执行程序后,该可执行程序就可以独自运行,不再需要库了。

缺点:

  • 使用静态库生成可执行程序会占用大量空间,特别是当有多个静态程序同时加载而这些静态程序使用的都是相同的库,这时在内存当中就会存在大量的重复代码。

动态库

动态库是程序在运行的时候才去链接相应的动态库代码的,多个程序共享使用库的代码。一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。

在可执行文件开始运行前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接。

在这里插入图片描述
优点:

  • 节省磁盘空间,且多个用到相同动态库的程序同时运行时,库文件会通过进程地址空间进行共享,内存当中不会存在重复代码。

缺点:

  • 必须依赖动态库,否则无法运行。

静态库的打包与使用

为了更容易理解,下面演示动静态库的打包与使用时,都以下面的八个文件为例,其中四个源文件Add.c,Sub.c,Mul.c,Div.c四个头文件Add.h , Sub.h,Mul.h,Div.h。

为了便于观看,都放入到一个展示:

//Add.c
#include "Add.h"


int Add(int x,int y)
{
    return x + y;
}

//Add.h
#pragma once

#include <stdio.h>
extern int Add(int,int);

//Div.c
#include "Div.h"

int Div(int x,int y, int *code)
{
    *code = 0;
    if(y == 0) 
    {
        *code = -1;
        return -1;
    }
    return x / y;
}

//Div.h
#pragma once

#include <stdio.h>

extern int Div(int,int,int*);

//Mul.c
#include "Mul.h"

int Mul(int x,int y)
{
    return x * y;
}

//Mul.h
#pragma once

#include <stdio.h>

extern int Mul(int,int);

//Sub.c
#include "Sub.h"

int Sub(int x,int y)
{
    return x - y;
}

//Sub.h
#pragma once

#include <stdio.h>

extern int Sub(int,int);

在这里插入图片描述

打包

我们使用Makefile来进行打包操作

static-lib=libmymath.a

$(static-lib):Add.o Div.o Mul.o Sub.o
	ar -rc $@ $^
%.o:%.c
	gcc -c $<
#Test:Add.o Div.o Mul.o Sub.o TestMain.o
#	gcc -o $@ $^

.PHONY:output
output:
	mkdir -p mymath_lib/include
	mkdir -p mymath_lib/lib
	cp -f *.h mymath_lib/include
	cp -f *.a mymath_lib/lib

.PHONY:clean
clean:
	rm -rf *.o *.a mymath_lib

第一行是替换,$(static-lib)就相当于libmymath.a
在这里插入图片描述
在这里插入图片描述

output操作是为了封装:

在这里插入图片描述

使用

在这里插入图片描述
此时使用gcc编译main.c生成可执行程序时需要携带三个选项:

  • -I:指定头文件搜索路径。
  • -L:指定库文件搜索路径。
  • -l:指明需要链接库文件路径下的哪一个库。

说明一下:

  • 因为编译器不知道你所包含的头文件add.h在哪里,所以需要指定头文件的搜索路径。
  • 因为头文件add.h当中只有my_add函数的声明,并没有该函数的定义,所以还需要指定所要链接库文件的搜索路径。
  • 实际中,在库文件的lib目录下可能会有大量的库文件,因此我们需要指明需要链接库文件路径下的哪一个库。库文件名去掉前缀lib,再去掉后缀.so或者.a及其后面的版本号,剩下的就是这个库的名字。
  • -I,-L,-l这三个选项后面可以加空格,也可以不加空格。

动态库的打包与使用

打包

我们使用Makefile来进行打包操作

dy-lib=libmymath.so

$(dy-lib):Add.o Div.o Mul.o Sub.o
	gcc -shared -o $@ $^
%.o:%.c
	gcc -fPIC -c $<

.PHONY:output
output:
	mkdir -p mymath_lib/include
	mkdir -p mymath_lib/lib
	cp -f *.h mymath_lib/include
	cp -f *.so mymath_lib/lib

.PHONY:clean
clean:
	rm -rf *.o *.so mymath_lib

在这里插入图片描述
output操作同样是为了封装

使用

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp使用openlayers加载地图服务

uniapp使用openlayers加载地图服务 <!-- 地图组件 --> <template><view id"myMap" :regionChangeItem"regionChangeItem" :change:regionChangeItem"olRender.selectAdministrativeRegion":tagSelectProducetagSelectProduce :ta…

数字图像处理 使用C#进行图像处理九 实现傅里叶变换

一、简述 傅立叶变换将图像分解为其正弦和余弦分量。换句话说,它将图像从空间域变换到频率域。这个想法是任何函数都可以用无限正弦函数和余弦函数之和来精确近似。傅里叶变换是实现此目的的一种方法。 网上有很多关于傅里叶变换的文章,这里就不进行赘述了,这里主要结合代码…

JS:36种原生JS数组方法(8种改变原数组方法,28种不涉及数组改变的方法)

一、改变原数组方法 1.push() 作用&#xff1a;向数组的末尾添加一个或多个元素 返回&#xff1a;添加后数组的长度。 <script>let arr [1, 2, 3];console.log(arr.push(4)); //4console.log(arr); //[1, 2, 3, 4]console.log(arr.push(2, 4)); //6console.log(arr);…

cad转shp再转3dtiles生成白模

1、准备CAD数据 2、arcgis中添加cad数据 添加面 cad中的标高字段是能带进arcgis中的&#xff0c;如果这个数据是建筑高度&#xff0c;可以直接用了 3、转shp 4、shp转3dtiles白模 cesiumlab中shp转3dtiles白模效果一

新零售SaaS架构:什么是线上商城系统?

零售商家为什么要建设线上商城 传统的实体门店服务范围有限&#xff0c;只能吸引周边500米内的消费者。因此&#xff0c;如何拓展服务范围&#xff0c;吸引更多消费者到店&#xff0c;成为了店家迫切需要解决的问题。 缺乏忠实顾客&#xff0c;客户基础不稳&#xff0c;往往是…

buuctf warmup

1.代码审计&#xff1a; <?phphighlight_file(__FILE__);class emmm //定义了一个类{public static function checkFile(&$page) 类里面又申明创建了一个函数{$whitelist ["source">"source.php","…

安装汇春MDTIDE以及HI-TECH PICCv9.83(PICC语言编译器)

最近了解了汇春一款8位通用型MCU----MDT10F684&#xff0c;所以这里安装一下IDE以及配置一下环境。 1.安装汇春MDTIDE 去到官网下载对应的开发包&#xff0c;我不知道里面内容是否一致。 Flash/MTP MCU (yspringtech.com) 不要点说明书下载&#xff0c;点了没反应&#xff0…

借助ChatGPT提高编程效率指南

PS: ChatGPT无限次数&#xff0c;无需魔法&#xff0c;登录即可使用,网页打开下面 一、借助ChatGPT提高编程效率指南 随着计算机技术的飞速发展&#xff0c;编程已经成为了现代社会中一个非常重要的技能。对于许多人来说&#xff0c;编程不仅是一项工作技能&#xff0c;而且是…

docker之自己制作jdk镜像

一&#xff0c;下载想要制作的镜像的对应jdk&#xff08;自行下载&#xff09;&#xff0c;本文使用jdk17&#xff08;因为自己的springboot项目时在jdk17下开发的&#xff0c;悲&#xff01;&#xff01;&#xff01;&#xff0c;再加上没有在官网上找到对应镜像&#xff0c;只…

ubuntu22.04 在wifi网络正常使用的情况下创建热点连接

ubuntu22.04 在wifi网络正常使用的情况下创建热点连接 在ubuntu22.04版本中正常通过设置打开wifi热点会取消正常的wifi网络连接 接下来让我们一起尝试在wifi网络正常的情况下创建热点连接 查看硬件是否支持 iw list | grep AP #查看是否支持AP模式 Device supports AP-side…

小米官网登录注册的滑动效果

小米官网登录注册的滑动效果 登录组成页面 <div class"client"><div class"userbox"><div class"title"><a href"javascript:;" class"active" id"DL">登录</a><a href&quo…

250+可用的 AI 资源网站

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 这里是关于AI网站的一份资源列表。欢迎访问该链…

message: apoc.meta.data is unavailable

报错内容 Traceback (most recent call last):File "/langchain-master/templates/neo4j-semantic-ollama/ingest.py", line 9, in <module>graph Neo4jGraph()File "/root/anaconda3/envs/sakura/lib/python3.9/site-packages/langchain_community/gra…

智慧农业新篇章:DSSAT模型、APSIM模型、WOFOST与PCSE模型综合应用,引领作物生长模拟与产量预测新潮流

目录 ★WOFOST模型与PCSE模型应用 ★基于R语言APSIM模型进阶应用与参数优化、批量模拟 ★最新DSSAT作物模型建模方法及应用 ★基于Python语言快速批量运行DSSAT模型及交叉融合、扩展应用 ★R语言与作物模型&#xff08;以DSSAT模型为例&#xff09;融合应用 ★遥感数据与…

酷开科技以消费者需求为导向冲刺OTT行业的星辰大海

通过大屏营销、互动营销等方式&#xff0c;提升品牌认知度和市场竞争力。酷开科技始终坚持以消费者的需求为导向&#xff0c;致力于为品牌方和消费者搭建高效、准确的沟通桥梁&#xff0c;开创OTT大屏营销新纪元。 伴随技术发展&#xff0c;智能电视已经从“尝鲜”变成了主流产…

C# Web自动化--Selenium入门

安装依赖库 需要引用的核心库是Selenium.RC&#xff0c;Selenium.Support&#xff0c;Selenium.WebDriver 然后再需要引用 浏览器驱动库&#xff0c;这里我以IE浏览器为例&#xff0c;Chrome使用方式跟IE是一样的&#xff0c;程序包名称为Selenium.WebDriver.ChromeDriver。 …

静电ESD整改:原因、影响与解决方案详解?|深圳比创达电子

静电&#xff08;ESD&#xff09;是在日常生活和工作中常见的现象&#xff0c;但它可能对电子设备和器件造成严重的损坏。本文将介绍静电ESD的定义、原因、影响以及解决方案&#xff0c;帮助大家更好地了解ESD问题&#xff0c;并采取相应的整改措施。 一、静电ESD的定义 静电…

技术驱动校园招聘:Java+SpringBoot+Vue的实践之旅

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

【Linux操作系统】:Linux进程概念(2)

一、Z(zombie)-僵尸进程 1.僵尸进程概念 故事 张三每天都有跑步的习惯&#xff0c;这一天他和往常一样跑步&#xff0c;跑了两三圈&#xff0c;突然跑在它前面的一个人倒在地上不动了&#xff0c;作为热心市民张三赶紧报警并且拨打120。很快120就来了&#xff0c;但是没过几分…

Docker单机下的容器网络管理

Docker容器网络管理 容器网络类型 Docker安装以后&#xff0c;会在我们的主机上创建三个网络 docker network ls可以看到有bridge、host和none三种网络类型 我们先把ubuntu的网络环境配置一下 docker run -it ubuntu apt update apt install net-tools iputils-ping curl这…