动静态库以及动态链接

文章目录

  • 静态库
    • 制作静态库
    • 如何使用静态库
  • 动态库
    • 动态库的制作
    • 动态库的使用
    • 动态链接

库是给别人用的,所以库中一定不存在main函数。库一般会有lib前缀和后缀,去掉前缀和后缀才是库名

静态库

静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。

库制作的本质就是把库中的源文件全部翻译成.o目标二进制文件,然后打包。
Linux中可以使用 gcc -c 选项将源文件翻译成.o文件。

制作静态库

制作静态库就只需要把所有的.h文件给用户,.h就相当于使用说明书,然后再把我们打包好的静态库,把他们放到一起给用户就可以了。
在这里插入图片描述
静态库打包可以用ar命令,可以使用Makefile。

插入图片描述](https://img-blog.csdnimg.cn/direct/1b468975a41a4183bbf285058ef34a64.png)

这个Makefile就可以实现把打包库文件,然后使用make Output 就可以把头文件以及库文件一起打包放到一个文件,然后就只用打包交给用户就行了。
在这里插入图片描述

如何使用静态库

假设我们现在有一个刚才打包好的库,然后我们要使用它,应该怎么用?
这是库提供的头文件的内容。
在这里插入图片描述

这是源代码:

#include <stdio.h>
#include "mymath.h"                                                                                                                                                           
int main(){printf("3 + 2 = %d\n",add(3,2));printf("3 - 2 = %d\n",sub(3,2));return 0;
}

如果直接编译,肯定会报错
在这里插入图片描述
会提示找不到库提供的头文件,因为C语言在编译的时候,只会在系统特定的目录下和当前目录下查找头文件,库的头文件既不在当前目录下也不在系统的特定目录下当然找不到了,所以我们可以直接把头文件拷贝到系统目录下/user/include。
但是也可以使用gcc的-i选项指定搜索头文件的目录:
在这里插入图片描述
这时提示找不到库里面的方法,因为我们的是第三方库,需要告诉编译器我们要链接那个库,就需要gcc的-l选项:
在这里插入图片描述
这是有提示找不到库,因为编译器只会在默认路径(/usr/lib64)下搜索库,我们需要使用-L选项指定搜索库的路径。
在这里插入图片描述
这是就编译成功了,这就是使用静态库的大概流程,如果觉得太麻烦的话,最简单的办法就是把头文件和库都拷贝到系统的默认路径中。

动态库

动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

动态库的制作

动态库依然是把.o文件打包,然后把.h和打包好的动态库一起交给用户,只不过动态库在形成.o是需要fPIC与位置无关码,打包.o文件直接使用gcc -shared 即可。
在这里插入图片描述

在这里插入图片描述

动态库的使用

动态库的使用和静态库一样,使用gcc命令,找不到头文件就用-i选项,-l指定需要链接的库,-L指定库的路径。
在这里插入图片描述
但是在运行的时候会有一些问题
在这里插入图片描述
我们可以使用ldd命令来查看一个可执行程序链接的动态库:
在这里插入图片描述
会发现找不到我们指定的库,这是因为我们虽然指定了库的路径,但是是给编译器指定的,程序编译成功成为可执行程序之后就和编译器没关系了,静态库没有这个问题是因为静态库是直接把自己需要的代码给自己拷贝了一份,而动态库是需要在运行的时候去动态库中找使用的函数,所以使用动态库链接的程序在运行的时候和库是强关联的。解决这个问题有很多种方法:

  1. 就是把头文件和库直接拷贝到系统的默认搜索路径中,即安装到系统。
  2. 使用软连接,可以在当前路径下或者库中建立软链接,因为动态库默认是会在当前路径下搜索的。
  3. 系统中有和环境变量LD_LIBRARY_PATH,可以把链接的动态库的路径添加到这个环境变量中,系统在搜索时会同时搜索这个环境变量中的路径。
  4. 直接更改系统的配置文件(etc/ld.so.conf.d/)
    在这里插入图片描述

gcc默认是动态连接的,但是个别库,如果只提供静态库(.a),gcc也没有办法,只能局部性的把指定的静态库进行静态连接,其他库正常进行动态链接,如果使用-static,对于该可执行程序,所有的库就都必须静态链接,对于同一组库,如果动态库和静态库都提供,gcc默认使用动态库。

动态链接

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

使用了动态库的程序,在加载的时候,除了自己的代码数据需要的数组需要加载之外,使用到的动态库也是需要加载的,一般在虚拟地址空间中用映射的位置是,堆区和栈区之间的共享区。

程序被编译好之后,还没有被加载时它的内部其实就已经充满了各种各样的地址(函数,变量等),所谓的函数名变量名什么的在程序被编译好之后就都变成了地址,程序在编译的时候,对代码等进行编制,其实也是遵守我们虚拟地址空间的那一套的,所以虚拟地址空间不仅仅是OS的概念,更是一种标准。编译器在进行编译的时候,也要按照这样的规则编译可执行程序,这样才能在加载的时候,进行磁盘文件到内存后和进程空间进行映射。这种可执行程序为ELF格式的可执行程序。

因此程序内部的各种地址也是虚拟地址,程序在跳转到时候,需要执行到哪个虚拟地址的代码,根据页表直接找到对应的程序然后执行就可以了,因此CPU的每一次执行基本上都需要查表,这种虚拟地址也可以用基地址+偏移量的方式来表示,一般基地址是0,偏移量的范围[0,FFFFFFFF],这种地址成为逻辑地址,虚拟地址空间的这种模式为平坦模式。

我们知道位置有绝对位置和相对位置,同理编址的方式也有绝对编址和相对编址,而在我们代码中用到的库中的函数一般用的都是相对编制即相对于库的起始地址自己的位置,因为库在被加载的时候映射的位置不是固定的,每次映射的位置都是不一的,只用使用这样 库的名字 + 偏移量 的这种方式,才能保证库在加载是可以在共享区的任意位置进行加载。所以当库别加载之后地址就是确定的,然后用库的起始地址带起库的名字就可以很好的找到库中的任意函数。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

引入线程的贪吃蛇风骚走位

1.在main函数中分别引入线程t1 和线程 t2 一个线程用来刷新界面&#xff0c;一个线程用来改变方向 2.刷新界面函数&#xff0c;无限次刷新 3. 也是无限循环while(1) 定义key 从键盘获取输入方向&#xff0c;赋值给dir; 4.在初始化函数中确定蛇向有行走为方向 5.从改变方向的函数…

ESLint 、 e2e test 学习

Lint和Format的区别&#xff1a; Lint只会告诉你代码中的错误或者不符合规范的地方&#xff0c;而Format是用来对格式作调整的 HTML/tpl&#xff1a;HTMLLint CSS/SCSS&#xff1a;Stylelint JS/JSX&#xff1a;Eslint JSLint&#xff1a;古老&#xff0c;不能配置和扩展JSHin…

CentOS安装CRI--containerd

前言 CRI&#xff0c;Container Runtimes&#xff0c;通常直译成容器进行时因为kubernetes&#xff0c;从1.24开始&#xff0c;移除了Dockershim&#xff0c;需要额外安装CRI&#xff0c;保障Pod能顺利运行。网上有很多容器进行时的工具&#xff0c;本文采用containerd工具。 …

Vue 使用Canvas画布手写电子版签名 保存 上传服务端

电子版签名效果 定义画布 <canvas width"500"height"250"ref"cn"mousedown"cnMouseDown"mousemove"cnMouseMove"mouseup"cnMouseUp"style"width:500px;height: 250px;background-color:snow;padding: 10p…

ros2 node 之间的通信方式之 —— Topic通信案例

文章目录 ros2 node 之间的通信方式之 Topic通信Topic 通信案例1、创建工作空间2、创建功能包3、编写发布者和订阅者代码3.1 topic_helloworld_pub.cpp3.2 topic_helloworld_sub.cpp 4、编写CMakeLists.txt5、编译工作空间下的功能包6、运行结果 ros2 node 之间的通信方式之 To…

attempt to compare nil with number -- 黑马点评出现问题

问题情况 : 主要问题 : 调用lua执行redis时&#xff0c;有一个值会接受nil&#xff08;因为redis中没有该数据&#xff09;或者数值&#xff0c;当该值为nil时执行报错&#xff0c;因为会用到将该值与其他数字比较&#xff0c;故报错attempt to compare nil with number 当然…

opencv图像处理

1、图像滤波处理 通过滤波来提取图像特征&#xff0c;消除噪声。 常用滤波方式有&#xff1a;均值滤波、高斯滤波、中值滤波、双边滤波。 高斯滤波&#xff1a; blur_gray cv2.GaussianBlur(orgGray, (kernel_size, kernel_size), 0) orgGray&#xff1a;灰度图像&#xf…

Amazon云计算AWS之[2]弹性计算云EC2

文章目录 说明EC2基本架构Amazon机器映象&#xff08;AMI&#xff09;实例&#xff08;Instance&#xff09;弹性块存储&#xff08;EBS&#xff09; EC2关键技术地理区域和可用区域EC2通信机制弹性负载均衡监控服务自动缩放服务管理控制台 EC2安全及容错机制EC2弹性IP地址 说明…

STM32 HAL库F103系列之IIC实验

IIC总线协议 IIC总线协议介绍 IIC&#xff1a;Inter Integrated Circuit&#xff0c;集成电路总线&#xff0c;是一种同步 串行 半双工通信总线。 总线就是传输数据通道 协议就是传输数据的规则 IIC总线结构图 ① 由时钟线SCL和数据线SDA组成&#xff0c;并且都接上拉电阻…

线性代数基础3 行列式

行列式 行列式其实在机器学习中用的并不多&#xff0c;一个矩阵必须是方阵&#xff0c;才能计算它的行列式 行列式是把矩阵变成一个标量 import numpy as np A np.array([[1,3],[2,5]]) display(A) print(矩阵A的行列式是&#xff1a;\n,np.linalg.det(A))array([[1, 3],[2, …

【C++打怪之路Lv3】-- 类和对象(上)

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文(平均质量分82)&#…

C++链表操作入门

数据结构基础&#xff1a;链表操作入门 数据结构基础&#xff1a;链表操作入门链表的基本概念链表的基本操作输出链表插入节点删除节点查找值 完整的链表操作示例结语 数据结构基础&#xff1a;链表操作入门 在计算机科学中&#xff0c;数据结构是组织和存储数据的方式&#x…

论文解读:(CAVPT)Dual Modality Prompt Tuning for Vision-Language Pre-Trained Model

v1文章名字&#xff1a;Dual Modality Prompt Tuning for Vision-Language Pre-Trained Model v2文章名字&#xff1a;Class-Aware Visual Prompt Tuning for Vision-Language Pre-Trained Model 文章汇总 对该文的改进&#xff1a;论文解读&#xff1a;(VPT)Visual Prompt …

ClickHouse 数据类型、表引擎与TTL

文章目录 数据类型注意事项 表引擎1.TinyLog 引擎2.MergeTree 引擎3.ReplacingMergeTree 引擎4.AggregatingMergeTree 引擎5.SummingMergeTree 引擎6.CollapsingMergeTree 引擎7.Distributed 引擎 TTL列级 TTL表级TTL 数据类型 ClickHouse 数据类型Java 数据类型数据范围UInt8…

在控制台实现贪吃蛇

在控制台实现贪吃蛇 前备知识Win32APICOORD这个结构体的声明如下&#xff1a;GetStdHandle 函数GetConsoleCursorInfo 函数SetConsoleCursorInfo 函数 SetConsoleCursorPosition 函数getAsyncKeyState 函数 控制台窗口的大小以及字符打印介绍控制台中的坐标宽字符及本地化介绍s…

使用 Gradio 的“热重载”模式快速开发 AI 应用

在这篇文章中&#xff0c;我将展示如何利用 Gradio 的热重载模式快速构建一个功能齐全的 AI 应用。但在进入正题之前&#xff0c;让我们先了解一下什么是重载模式以及 Gradio 为什么要采用自定义的自动重载逻辑。如果你已熟悉 Gradio 并急于开始构建&#xff0c;请直接跳转到第…

UE4 拍摄、保存并浏览相册

效果&#xff1a; 1.新建CameraActor类 2.修改截图保存路径 3.编写BP_Camera蓝图 注意路径 Save Image函数要在执行拍照和BeginPlay事件执行一次 按钮执行拍摄事件 3.编写UMG蓝图 技巧&#xff1a;让Index加1、减1循环赋值 4.把BP_Camera挂在玩家上

SVN--基本原理与使用(超详细)

目录 一、SVN概述二、SVN服务端软件安装三、SVN服务端配置四、SVN客户端软件安装与使用五、SVN三大指令六、SVN图标集与忽略功能6.1 图标集6.2 忽略功能 七、SVN版本回退八、SVN版本冲突九、SVN配置多仓库与权限控制9.1 配置多仓库9.2 权限控制 十、服务配置与管理十一、模拟真…

新建云仓库

1.GitHub新建云仓库&#xff1a; LICENSE:开源许可证&#xff1b;README.md:仓库说明文件&#xff1b;开源项目&#xff1b;cocoaPodsName.podspec: CocoaPods项目的属性描述文件。 2.Coding新建云仓库&#xff1a; 备注&#xff1a; Coding新建项目&#xff1a;

每日一题(力扣45):跳跃游戏2--贪心

由于题目已经告诉了我们一定可以跳到&#xff0c;所以我们只需去考虑前进最快的方法。即 判断当前下一步能跳的各个位置中&#xff0c;哪个能带你去去向最远的地方&#xff08;why&#xff1f; 因为其他位置所能提供的最大范围都没最远那个大&#xff0c;所以最远的那个已经可以…