基础IO2

文章目录

  • 磁盘结构
  • 磁盘存储结构
  • 磁盘的逻辑结构
  • 引入文件系统
  • 理解文件系统
    • inode 映射 data blocks
    • 文件名与inode的关系
    • dentry树
    • 文件描述符与进程之间的关系
  • 深刻理解软硬链接
    • 软链接
    • 硬链接
  • 动静态库
    • 静态库
      • 1. 手动制作静态库
      • 2.调用静态库
        • (1)安装到系统
        • (2)自己指定查找路径
        • (3)自己创建include和lib,发布给别人
    • 动态库重复上述操作
        • (1)安装到系统
        • (2)自己指定查找路径
        • (3)自己创建include和lib,发布给别人
        • 解决方法 (环境centos7)
        • 注意事项
  • 动态库的理解,动态库加载和进程地址空间

在文件1当中我们主要讲解了什么是文件描述符?同时提出了文件内核缓冲区以及用户级缓冲区的概念,理解了什么是重定向。

以上的都是对于已经打开了的文件,他们是存在内存当中的。可以一个磁盘可能有10000个文件,已经打开了100个,那么剩余的9900个文件呢?-》那肯定就是在磁盘当中喽!那么我们想要打开一个在磁盘当中的文件首先这个磁盘当中得有这个文件,其次我们需要知道这个文件的地址。可是每一个文件都有一个地址,那么磁盘就一定要对这些文件进行管理

举个例子🌰:

在生活当中,我们从网上买了一个东西,可能并不是快递一到了我们就去拿了,一般都会放在菜鸟驿站当中,那么菜鸟驿站肯定不会说直接把这些快递堆一块,我们来拿快递的时候光找都要找1~2小时,而是把每一个快递都管理起来,比如每一个快递都有一个编号: 17 − 1024 17-1024 171024代表着17号柜子1024号。这个编号对应其中一个快递,并且是唯一的。这就相当于磁盘当中文件的地址。对于每一个快递都需要这么管理起来,同时如果哪个柜子太满,另一个柜子又太空闲,那么对于驿站管理员来说就需要对快递进行管理等等操作,我们把这样的行为称为快递系统,同时在磁盘当中也需要一个文件系统来管理没有被打开的文件。

那么我们就需要解决:

  • 磁盘是如何管理这些文件的呢?
  • 如何理解文件地址呢? 这里我们知道文件地址可以定位文件 这里我们知道文件地址可以定位文件 这里我们知道文件地址可以定位文件

磁盘结构

在这里插入图片描述

上图是我们台式电脑中机械硬盘拆开了之后的样子,这里我们主要谈两个,磁盘和磁头,我们磁盘再不断地顺时针旋转,然后磁头可以左右移动来读取磁盘当中的数据(俯视图)。

磁盘存储结构

磁盘是由盘片构成的,每一个盘片有两面或者称为表面,表面覆盖着磁性记录材料。磁盘中央有一个可以旋转的主轴,他让盘片可以旋转起来,每个磁盘通常包含一个或者多个盘片。

在这里插入图片描述

如上图,其中我们一圈一圈的同心圆称为磁道每一个磁道划分为相同个数的扇区(只不过内层的间隙小,外层的间隙大并且每个面的扇区数是由最内层的扇区数决定的,每一个扇区之间有间隙隔开。每个扇区中可以存放 512 512 512字节的数据 ( 扇区是磁盘当中最基本的存储单元 ) (扇区是磁盘当中最基本的存储单元) (扇区是磁盘当中最基本的存储单元)

在这里插入图片描述

如上图,这里假设我们一共3片盘片,每一个盘片都会有两个磁头,就是说每一片盘片都有两个面,并且每一个面都会有一个磁头。

那么磁盘是如何读取数据的呢?

当我们盘片在旋转的过程中,移动到对应的磁道中,通过旋转再定位到一个一个的扇区当中。 这里可以把盘面上一粒微小的灰尘都看做一块巨石,如果磁头碰到了这样的一块巨石就会停下来,撞到盘面 − − 所谓的读 / 写 这里可以把盘面上一粒微小的灰尘都看做一块巨石,如果磁头碰到了这样的一块巨石就会停下来,撞到盘面--所谓的读/写 这里可以把盘面上一粒微小的灰尘都看做一块巨石,如果磁头碰到了这样的一块巨石就会停下来,撞到盘面所谓的读/

  • 所以旋转的本质是为了确定是哪个扇区。

  • 而磁头臂在半径中横向移动是为了确定在哪一个磁道。

同时我们每个面的每个磁头移动的时候都是一起移动的,这里我们管每个面的每个磁头共同形成的那个面称为柱面 ( c y l i n d e r ) (cylinder) (cylinder)。如下图:

在这里插入图片描述

并且我们磁盘中柱面有6个磁头所在的磁道构成,从外向内使用,依次编号为 [ 0 , 1 , 2 , 3... ] [0,1,2,3...] [0,1,2,3...],盘面也是从上往下依次编号为 [ 0 , 1 , 2 , . . . ] [0,1,2,...] [0,1,2,...]

如何定位一个扇区呢?

当我们需要定位一个扇区的时候我们需要定位到底在哪一个柱面(cylinder) 上,其次需要定位在哪一个 磁头(header) 上,最后才是定位到哪一个扇区(sector) 当中。所以在磁盘当中我们管这个叫做CHS寻址。

我们在linux中可以使用fdisk -l /dev/vda来查看我们的磁盘情况:

在这里插入图片描述

如果是虚拟机的话则是/dev/sda。如上图,可以说明确实是存在扇区这个概念的。

磁盘的逻辑结构

在这里插入图片描述

如上图,我们可以把每一个磁道都拉直,同时扇区的下标是从1开始的,这样每一个扇区都有一个数组下标位置了,这个位置下标称为LBA地址,但是在磁盘当中真是的物理结构还是我们上述讨论的结构,所以磁盘当中还是会通过CHS去寻址,但是我们操作系统却可以使用LBA地址去转化CHS地址。

上述我们说过,一个磁盘可以有多个盘片,每一个盘片又有俩个磁头,这里假设我们有三个盘片那就是6个磁头,每一个磁头都是共同移动的。6个磁头指向6个磁道,这些相同半径磁道构成一个柱面,所以我们磁盘可以看做是一个个柱面卷起来的圆柱体。并且每一个磁道中的扇区个数是相同的,那么把这个圆柱体剪开就相当于把每个磁道的扇区展开,这不就是一个二维数组吗:

在这里插入图片描述

那么多个柱面合在一起不就是一个三维数组吗,同时无论是二维数组还是三维数组,我们都可以使用一个一维数组来表示:

在这里插入图片描述

如上图,所以以这样的逻辑结构我们就可以使用数组下标位置来表示扇区位置 L B A LBA LBA(logical block address)地址。那么LBA地址是如何与CHS地址进行相互转换的呢?

C H S = > L B A CHS\ =>\ LBA CHS => LBA 柱面号 ∗ 柱面扇区总数 ( 磁头数 ∗ 磁道扇区总数 ) + 磁道号 ∗ 单个磁道扇区总数  + 扇区号 − 1 柱面号*柱面扇区总数(磁头数*磁道扇区总数)\ +\ 磁道号*单个磁道扇区总数\ + 扇区号-1 柱面号柱面扇区总数(磁头数磁道扇区总数) + 磁道号单个磁道扇区总数 +扇区号1

同时以上式子有以下关系:

柱面扇区总数 > 单个磁道扇区总数 > 扇区号 − 1 柱面扇区总数 > 单个磁道扇区总数 > 扇区号-1 柱面扇区总数>单个磁道扇区总数>扇区号1

L B A = > C H S LBA\ =>\ CHS LBA => CHS:根据上述关系可用LBA反推CHS

  • 柱面号 = L B A / / 柱面扇区总数 ( 磁头数 ∗ 磁道扇区总数 ) LBA\ //\ 柱面扇区总数(磁头数*磁道扇区总数) LBA // 柱面扇区总数(磁头数磁道扇区总数) (//表示整除,向下取整)
  • 磁道号 = ( L A B % 柱面扇区总数 ) / / 磁道扇区总数 (LAB\ \%\ 柱面扇区总数)\ //\ 磁道扇区总数 (LAB % 柱面扇区总数) // 磁道扇区总数
  • 扇区号 = ( L A B % 磁道扇区总数 ) + 1 (LAB\ \%\ 磁道扇区总数)+1 (LAB % 磁道扇区总数)+1 (LBA的下标是从1开始的)

所以从现在开始我们操作系统定位扇区是需要使用LBA地址即可。但是实际当中一个扇区大小为 512 512 512字节,还是太小了,所以一般操作系统访问磁盘都是以 4 K B 4KB 4KB大小进行访问,也就是 8 个扇区 8个扇区 8个扇区我们管着8个扇区叫做一个块

在这里插入图片描述

如上图,我们知道了块号也可以知道LBA地址,知道了LBA地址也就可以转化为CHS地址,这样操作系统就可以定义磁盘当中任意一个扇区了,能找到一个扇区同时也可以找到多个扇区,以这种方式我们操作系统就可以管理文件了。

引入文件系统

所以我们磁盘可以看做是一个一个的块组成的,知道了磁盘的总大小我们就知道了块的个数 磁盘总容量 / 4 K B 磁盘总容量/4KB 磁盘总容量/4KB,那磁盘是一个一个去管理这个4kb大小的块吗?有些磁盘的空间可以会有几TB,或者几十TB,这样的话管理的成本太高,所以一般磁盘管理是对磁盘进行分区,同时每个分区还要进行分组,只要把每一个组管理好了,就相当于把分区管理好了,每一个分区管理好了那么整个磁盘也就管理好了。

举个生活中的例子🌰:就像我们国家960万平方千米的国土,分为了一个又一个的省,每个省又分为了一个有一个的市,把每一个市管理好了,就相当于把省管理好了,把每一个省管理好了就可以把整个国家管理好。

在这里插入图片描述

如上图,在linux中我们/dev代表的就是磁盘,而vda1代表的就是当前磁盘的分区。

对于不同磁盘分区可以使用不同的文件系统,这样即使一个分区挂掉了其他分区也不受影响。我们主要来讲解ext系列中的ext2文件系统。

如上图所示,对于每一个分组而言有一下几种结构:

  • Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相
    同的结构组成。政府管理各区的例子
  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量, 未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
  • GDT,Group Descriptor Table:块组描述符,描述块组属性信息。
    块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没
    有被占用
  • inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
  • block位图(blockBitmap):每个bit表示一个block是否空闲可用。
  • inode节点表:存放文件属性 如 文件大小,所有者,最近修改时间等
  • 数据区:存放文件内容

在这里插入图片描述

如上图,文件 = 内容 + 属性,其中属性是存储在 i n o d e inode inode结构体中,我们只来讨论大小为 128 128 128字节的情况。

分组当中每一个文件都会有一个 i n o d e inode inode结构体里面会有一个 i 结点编号 i结点编号 i结点编号,他们存储在 i n o d e t a b l e inode\ table inode table中,而一个文件对应的内容则是存储在 D a t a b l o c k s Data\ blocks Data blocks中。同时我们的 i n o d e b i t m a p inode\ bitmap inode bitmap就是一个位图,他表示的是我们 i n o d e t a b l e inode\ table inode table中的某一个 i n o d e 号 inode号 inode是否被使用,在 l i n u x linux linux中我们可以使用 l s − i ls\ -i ls i来显示 i n o d e inode inode号。

在这里插入图片描述

i n o d e inode inode结构体中还会存在 b l o c k n u m [ ] block\ num[] block num[]数组,它里面存储着一个文件对应的数据块号,数据块存储在 d a t a b l o c k s data\ blocks data blocks中,每个大小都为 4 k b 4kb 4kb

而数据块也有一个 b l o c k b i t m a p block\ bitmap block bitmap表示这数据块是否被使用。

G r o u p D e s c r i p t o r T a b l e Group\ Descriptor\ Table Group Descriptor Table:里面存储着是当前分组的 i n o d e t a b l e inode\ table inode table d a t a b l o c k s data\ blocks data blocks的使用情况(已使用多少个,还有多少个空闲)。

S u p e r b l o c k Super\ block Super block:超级块,表示文件系统。它存储则是整个分区中的 i n o d e inode inode b l o c k block block个数,一般一个分区当中不会每一个分组都会有一个 s u p e r b l o c k super\ block super block,当一个 s u p e r b l o c k super\ block super block出问题之后,整个文件系统就崩了,这时候只需要拷贝其他的 s u p e r b l o c k super\ block super block信息即可。

理解文件系统

对于每一个分区而言我们都是一整套的 i n o d e inode inode,也就是说我们不同分区当中可以会有同一个 i n o d e = = 100 inode==100 inode==100的文件,各个分区相互独立。那么文件系统是如何分配 i n o d e inode inode的呢?

在这里插入图片描述

如上图,对于每一个分组而言我们只需要设置每个分组的起始 i n o d e inode inode即可,对于 d a t a b l o c k data\ block data block也是如此。

  1. 如何删除一个文件?

我们拿着对应的 i n o d e inode inode号,求跟起始 i n o d e inode inode比较找到对应的分组,然后减去起始 i n o d e inode inode去分组当中的bitmap中把 1 − > 0 1\ ->\ 0 1 > 0即可,所以对于删除一个文件我们只是把对应的bit位由1变为0,所以删除了一个文件我们其实是可以恢复的,但这只是在当前位置的 i n o d e inode inode号没有被再次使用的情况。

  1. 如何新增一个文件

去每一个组当中的 G r o u p D e s c r i p t o r T a b l e Group\ Descriptor\ Table Group Descriptor Table i n o d e b i t m a p inode\ bitmap inode bitmap是否已满,如果没有满在遍历找出bit位为0,再把它置为1,然后返回当前位置 + s t a r t i n o d e start\ inode start inode

  1. 如何修改一个文件?

根据 i n o d e inode inode号找到一个文件的 i n o d e t a b l e inode\ table inode table去查看对应的 b l o c k n u m [ ] block\ num[] block num[]然后把对应的数据块 ( 4 k b 大小 ) (4kb大小) (4kb大小)拷贝到磁盘当中,修改完之后再拷贝回去。这里还需要注意我们的 d a t a b l o c k s data\ blocks data blocks其实可以分组存储的。

inode 映射 data blocks

对于一个分组而言就是一开始所有的位置所需要的空间已经划分好了, S u p e r b l o c k Super\ block Super block把每一个分区中的 I n o d e Inode Inode b l o c k block block数量已经给定了,那么每一个分组的 I n o d e Inode Inode b l o c k block block数量就也给定了,而且对于一个分组 ( 10 G B 为例 ) (10GB为例) (10GB为例)而言,其中除了 d a t a b l o c k s data\ blocks data blocks之外其他的结构可能也就占据 100 M B 100MB 100MB,其余的 9.9 G B 9.9GB 9.9GB都是有数据块占据的,那么一个 i n o d e inode inode也就 128 128 128字节,如果用一个整数来映射数据块号的话也就只能映射几十个。所以 i n o d e inode inode中采取多级指针的方式来指向数据块的,如下图:

在这里插入图片描述

如上图,我们 i n o d e inode inode有12个直接指向数据块,其他的一级间接块索也是指向一个 4 k b 4kb 4kb大小的数据块,只不过里面不存数据,而是存的其他数据块的标号,类似一个一维数组,那么一个编号假设需要4个字节,那一个块就可以存储 1024 1024 1024的数据块号,这1024个数据块可以指向的数据块总大小为 1024 ∗ 4 k b = = 4 M B 1024*4kb == 4MB 10244kb==4MB,同理我们二级索引表指向的数据块不存数据,存的是一级索引表的编号,那么可以指向的数据块总大小为 1024 ∗ 一级索引表大小 = = 4 G B 1024*一级索引表大小 == 4GB 1024一级索引表大小==4GB,三级索引就是40GB。

文件名与inode的关系

我们上述增删查改文件好像都是与inode有关,可以平常我们在linux中都是用的文件名,并且我们的文件名不存在$inode $结构体当中,那么我们是如何通过文件名找到文件的呢?

我们的目录也是文件,是文件就 = 内容 + 属性。

在这里插入图片描述

所以我们的目录存储的是文件名与 i n o d e inode inode的映射关系(互为映射),当我们想要查找文件的时候就需要去目录中查找对应文件名对应的 i n o d e inode inode号。所以现在我们就可以在来重新理解目录的 r w x rwx rwx权限,没有 r r r权限你就不能访问目录当中文件名与 i n o d e inode inode的映射关系,没有 w w w权限,就不能向目录文件中的数据块中写入,没有 x x x权限本质就是打不开文件。而且对于上述讲的文件系统而言,并不区分到底是文件还是目录,本质都是 i n o d e inode inode号。

那么为什么 l i n u x linux linux要使用这种方式呢?效率,对于我们查询字符串的时候,比较的时间为 O ( n ) O(n) O(n),而数字的比较为 O ( 1 ) O(1) O(1)

在这里插入图片描述

如上图,包括我们的拥有者和所属组也是整数来存储的,这也是为什么我们会有 u i d uid uid g i d gid gid的原因。

dentry树

现在我们知道了找到一个文件需要去目录当中去查找文件名对应的 i n o d e inode inode号,可是目录也是文件啊,目录的 i n o d e inode inode号谁来提供呢?

在这里插入图片描述

如上图,我们查找一个文件,需要解析目录找到对应的 i n o d e inode inode,上图我画的是依次往上解析,实际是从根目录往下解析的。而根目录的 i n o d e inode inode是直接给定的。

所以为什么每一个文件都要有路径呢?就是因为要通过路径层层外下递归去找到 文件,那么路径是谁给的呢?-> 进程,所以每一个进程都需要有一个cwd。

在这里插入图片描述

如上图,我们每一次解析路径都是访问磁盘的文件系统,这样效率太慢了,所以linux中就有一种内存结构 s t r u c t d e n t r y struct\ dentry struct dentry来对所访问的目录或者文件进行缓存,根目录则是本来就有的。所以当我们想要查询一个已经查询过的文件时,不要再按个解析路径了,只需要遍历这个dentry树即可。

所以为什么find 路径 -name 查询文件的时候第一次比较慢,之后就很快了呢?就是因为路径被缓存了。

文件描述符与进程之间的关系

在这里插入图片描述

如上图,对于打开一个文件,我们会先构建一个 d e n t r y dentry dentry结点,把结点挂在对应的目录底下,最后再创建一个 s t r u c t f i l e struct\ file struct file返回对应的 f d fd fd

同时文件的内容拷贝到文件内核缓冲区当中,这样属性有了内容也有了一个文件不就有了吗?

所以现在在一个磁盘的一个分区当中,我们已经可以找到任意一个文件了,可是我怎么知道我在哪一个分区呢?

  • 对于一个分区而言,需要包含一个根目录和若干普通目录
  • 同时一个分区必须经过"挂载"到目录当中,才可以被用户以路径的方式进行访问。

在这里插入图片描述

如上图,所以我们的一个分区天然就有路径,只要我们进入了某个被挂载的目录我们就相当于进入了某个分区。进入了分区我们就可以任意创建目录和文件。上文讲过任意一个文件都有路径,所以一个路径的前缀就代表着我们处于那个分区。

深刻理解软硬链接

软链接

在这里插入图片描述

如上图,ln -s + filename + 软连接之后的名称就可以为指定的文件创建软链接了,同时软连接是一个独立的文件,有自己的 i n o d e inode inode,它的文件内容存储的是所链接文件的路径。

⚠️: 同时软链接的文件前面的类型为l

那么为什么要有软链接呢?

  1. 如下图

在这里插入图片描述

⚠️: 我们建立软链接的时候最好使用绝对路径,不然找不到。

  1. 作为应用程序的快捷方式 | 快速定位一个文件,以最简单的方式进入。

在这里插入图片描述

硬链接

在这里插入图片描述

如上图,ln + filename + 硬连接之后的名称,同时硬链接之后的文件inode和原文件相同,那么右边的数字代表的什么意思呢?

右边的数字其实就是文件的引用计数,当文件为0的时候就会把文件彻底释放掉了。同时硬链接和源文件指向同一个文件,就类似两个指针指向同一片空间。

硬链接的作用:

  1. 对文件进行备份

在这里插入图片描述

  1. 统计目录当中有多少个子目录

在这里插入图片描述

在这里插入图片描述

所以我们18-2 == 16就可以计算出/目录下的目录个数。

⚠️:在linux中,不允许对目录创建硬链接(避免环状问题 . 和 . . 除外 .和..除外 ...除外):

在这里插入图片描述

动静态库

动静态库是把我们编译形成的.o文件的集合,就是把所有的.o打包,里面是我们头文件一些函数方法的实现,一般我们都需要跟头文件配合使用。

动态库:程序运行时加载

静态库:直接把函数的方法加载到调用的地方

静态库

1. 手动制作静态库

在这里插入图片描述

如上图,我们形成静态库的指令为ar -rc + lib+库名.a(.0.0.1) + 所需要的.o文件

− r : r e p l a c e ( 存在时替代 ) − c : c r e a t e ( 不存在时创建 ) -r:\ replace(存在时替代)\ -c:create(不存在时创建) r: replace(存在时替代) c:create(不存在时创建) ,同时对于库的名字,必须以 l i b lib lib为开头 . a .a .a结尾,同时.a后面可以增加版本信息(可加可不加)。

2.调用静态库

(1)安装到系统

l i n u x linux linux系统中, g c c gcc gcc默认会查找的头文件路径为 / u s r / i n c l u d e /usr/include /usr/include,默认查找的库路径为: / l i b 64 /lib64 /lib64,所以我们只需要把我们的头文件和我们的库放入系统的查找路径底下即可。

在这里插入图片描述

(2)自己指定查找路径

在这里插入图片描述

当我们不想安装到c标准库中的时候,在我们当前目录下只有库文件和.o文件的时候怎么办呢?那我们就需要指定我们自己的库。

gcc -main.c -l+库名,其中这个库名前面的 l i b lib lib和后面的 . a .a .a都不加。

同时由于使我们自己写的库, g c c gcc gcc只会去查找自己的默认路径 / u s r / i n c l u d e /usr/include /usr/include / l i b 64 /lib64 /lib64,所以我们还需要使用gcc main.c -L + 库所在路径,让 g c c gcc gcc除了在系统路径下查找之外,还要在我们指定的路径之下查找。

⚠️: 如果我们自己写的库名和系统的库名一样,那么系统先查找到哪个就用哪个。

(3)自己创建include和lib,发布给别人

一般软件都会把自己的代码封装为库,同时源文件放在 i n c l u d e include include目录下,而库文件放入 l i b 目录 lib目录 lib目录下,然后打包让别人下载下来使用自己的产品,我们也来模拟这个过程,只不过我们只是创建一个 o t h e r other other目录。

在这里插入图片描述

这里我们要多一个选项:gcc main.c -I + 自己的头文件路径,这样的话我们 g c c gcc gcc寻找头文件的时候除了会去找默认路径,还会去指定的路径中找头文件。

动态库重复上述操作

⚠️!!!: 在ubuntu20.04环境下,安装到系统也不管用,需要增加环境变量 (方法三)
方法4也可以。

(1)安装到系统

动态库的后缀为.so,同时对比静态库的不同是我们动态库形成可执行程序是用 g c c gcc gcc

在这里插入图片描述

如上图,gcc -o -shared形成共享文件,gcc -c fPIC, file Position ignore code(与位置无关码),这有这样才可以形成动态库。

同时由于我们是自己写的库,所以需要特殊指定查找的库。同时对于动态库而言,可以使用ldd+可执行程序可以查看依赖哪些动态库,如下图:

在这里插入图片描述

如上图,使用 f i l e file file + 可执行程序,可以查出来是动态链接还是静态链接

⚠️:这里只要我们把自己写的头文件安装到系统之后,在 m a i n . c main.c main.c中引用头文件就得使用 # i n c l u d e < m y _ s t d i o . h > \#include\ <my\_stdio.h> #include <my_stdio.h>

(2)自己指定查找路径

在这里插入图片描述

这个跟上述静态库一样不做解释,⚠️这里可能会有问题,我们到下一个方法一起说明。

(3)自己创建include和lib,发布给别人

在这里插入图片描述

如上图,我们发现此时运行我们的可执行程序,竟然找不到我们的动态库,这是为什么呢?

由于动态库我们是运行的时候加载的,使我们操作系统去加载,而我们前面的 g c c − I − L − l gcc\ -I\ -L\ -l gcc I L l都是告诉编译器去哪找,跟系统没关系,所以此时才会找不到。

解决方法 (环境centos7)
  1. 安装到系统,见 ( 1 ) (1) (1)
  2. 在系统路径建立我们库的软链接

在这里插入图片描述

  1. 在linux系统中查动态库,除了去找默认路径,还会去查环境变量-> L D _ L I B R A R Y _ P A T H LD\_LIBRARY\_PATH LD_LIBRARY_PATH
    env中如果没有也没关系,我是因为配置了vim才会有上面这个,此时我们只需要把我们的路径导入这个环境变量即可:

在这里插入图片描述

但是我们知道我们自己手动 e x p o r t export export的时候等重启 X S h e l l XShell XShell就会消失,如果你想要一直有,只需要在家目录下的 . b a s h r c .bashrc .bashrc文件中添加自己的路径即可:

  1. 全局配置路径
echo /home/dpj/linux_code/daily_code/dir > /etc/ld.so.conf.d/test.conf# 在/etc/ld.so.conf.d/创建一个文件(.conf),把当前路径输入到文件当中。

在我们系统会去 / e t c / l d . s o . c o n f . d / /etc/ld.so.conf.d/ /etc/ld.so.conf.d/这个目录下查找加载动态库的配置文件,我们如果想要系统知道我们的动态库位置,也可以在这个目录下创建一个 . c o n f .conf .conf后缀的文件(文件名随意),里面只需要写我们库所在的路径即可。⚠️: 此时我们的系统不是不知道链接哪一个而是找不到位置,所以我们需要给系统我们动态库的位置。

在这里插入图片描述

当我们创建完文件之后还需要使用ldconfig更新一下, 是 L 不是 i 😁 是L不是i😁 L不是i😁

上述4中方法中常用的是 ( 1 ) , ( 3 ) (1),(3) (1),(3),其他两个了解一下即可。

注意事项

在这里插入图片描述

如上图,当我们动静态库同时存在的时候优先使用动态库。如果我们使用的是动态库,然后我们把动态库删了,就会报错,而静态则不会。

在这里插入图片描述

  • 如上图使用 − s t a t i c -static static可以强制使用静态链接。

在这里插入图片描述

  • 如上图,如果我们只有静态库,但是默认使用动态链接, g c c gcc gcc没得选只能对.a局部进行动态链接,用什么方法拷贝什么方法。

动态库的理解,动态库加载和进程地址空间

在这里插入图片描述

动静态库会通过页表映射在进程地址空间中的堆栈之间(共享区)当中,当我们执行正文代码的时候执行到动态库的部分时会跳转到共享区当中然后再跳转回来继续执行。

那如果又有一个进程依赖这个动态库呢?

在这里插入图片描述

如上图,当一个新进程也依赖这个库的时候,页表会直接映射内存当中动态库的位置,并且动态库无需再另外加载一次,也就是动态库如果被多个进程所依赖只需要加载一次即可。这也是为什么默认使用动态库的原因,效率高。

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

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

相关文章

RPC-健康检测机制

什么是健康检测&#xff1f; 在真实环境中服务提供方是以一个集群的方式提供服务&#xff0c;这对于服务调用方来说&#xff0c;就是一个接口会有多个服务提供方同时提供服务&#xff0c;调用方在每次发起请求的时候都可以拿到一个可用的连接。 健康检测&#xff0c;能帮助从连…

ZD Soft Screen Recorder:电脑录屏软件

前言 ZD Soft Screen Recorder 是一款屏幕录制软件 安装环境 [名称]&#xff1a;ZD Soft Screen Recorder [版本]&#xff1a;11.7.2 [大小]&#xff1a;6.8MB [语言]&#xff1a;英文 [环境]&#xff1a;pc 链接: 百度网盘 请输入提取码 提取码: ua23 软件界面 1、双击…

某杀软环境下的添加账户

某杀软环境下的添加账户 我们在某个杀软环境下&#xff0c;正常添加账户一般是会被直接拦截的 白&#xff0b;黑 在这个环境下&#xff0c;白&#xff0b;黑是最实用的绕过方式&#xff0c;我们可以通过调用winapi来创建账户&#xff0c;这些代码再存储到dll里面&#xff0c…

《Spring 基础之 IoC 与 DI 入门指南》

一、IoC 与 DI 概念引入 Spring 的 IoC&#xff08;控制反转&#xff09;和 DI&#xff08;依赖注入&#xff09;在 Java 开发中扮演着至关重要的角色&#xff0c;是提升代码质量和可维护性的关键技术。 &#xff08;一&#xff09;IoC 的含义及作用 IoC 全称为 Inversion of…

【C++】set,map,multiset,multimap的介绍和使用

set、map、multiset、multimap set、multiset的介绍和使用1、关联式容器2、键值对3、树形结构的关联式容器4、setset的介绍set的定义set的使用 5、multisetmultiset的介绍multiset的使用 map、multimap的介绍和使用1、map的介绍map的定义insert插入函数map的迭代器find查找函数…

Midjourney基础命令和提示词

1 基础命令 1.1 /imagine prompt 生成图片的核心命令&#xff0c;prompt 后输入描述。 /imagine prompt: A majestic dragon flying over a misty mountain, cinematic lighting, 4K resolution 高级提示 1.1.1 基本参数 图片比例 --ar 图片比例 混乱 Aspect Ratios --…

【代码pycharm】动手学深度学习v2-04 数据操作 + 数据预处理

数据操作 数据预处理 1.数据操作运行结果 2.数据预处理实现运行结果 第四课链接 1.数据操作 import torch # 张量的创建 x1 torch.arange(12) print(1.有12个元素的张量&#xff1a;\n,x1) print(2.张量的形状&#xff1a;\n,x1.shape) print(3.张量中元素的总数&#xff1…

智云-一个抓取web流量的轻量级蜜罐v1.5

智云-一个抓取web流量的轻量级蜜罐v1.5 github地址 https://github.com/xiaoxiaoranxxx/POT-ZHIYUN 新增功能-自定义漏洞信息 可通过正则来添加相关路由以及响应来伪造 nacos的版本响应如下 日流量态势 月流量态势 抓取流量效果

【Android原生问题分析】夸克、抖音划动无响应问题【Android14】

1 问题描述 偶现问题&#xff0c;用户打开夸克、抖音后&#xff0c;在界面上划动无响应&#xff0c;但是没有ANR。回到Launcher后再次打开夸克/抖音&#xff0c;发现App的界面发生了变化&#xff0c;但是仍然是划不动的。 2 log初分析 复现问题附近的log为&#xff1a; 用户…

2024年11月16日 星期六 重新整理Go技术

今日格言 坚持每天进步一点点~ 一个人也可以是一个团队~ 学习全栈开发, 做自己喜欢的产品~~ 简介 大家好, 我是张大鹏, 今天是2024年11月16日星期六, 很高兴在这里给大家分享技术. 今天又是休息的一天, 做了很多的思考, 整理了自己掌握的技术, 比如Java, Python, Golang,…

go-zero(一) 介绍和使用

go-zero 介绍和使用 一、什么是 go-zero&#xff1f; go-zero 是一个基于 Go 语言的微服务框架&#xff0c;提供了高效、简单并易于扩展的 API 设计和开发模式。它主要目的是为开发者提供一种简单的方式来构建和管理云原生应用。 1.go-zero 的核心特性 高性能&#xff1a; g…

VUE+SPRINGBOOT实现邮箱注册、重置密码、登录功能

随着互联网的发展&#xff0c;网站用户的管理、触达、消息通知成为一个网站设计是否合理的重要标志。目前主流互联网公司都支持手机验证码注册、登录。但是手机短信作为服务端网站是需要付出运营商通信成本的&#xff0c;而邮箱的注册、登录、重置密码&#xff0c;无疑成为了这…

多目标优化算法:多目标蛇鹫优化算法(MOSBOA)求解ZDT1、ZDT2、ZDT3、ZDT4、ZDT6,提供完整MATLAB代码

一、蛇鹫优化算法 蛇鹫优化算法&#xff08;Secretary Bird Optimization Algorithm&#xff0c;简称SBOA&#xff09;由Youfa Fu等人于2024年4月发表在《Artificial Intelligence Review》期刊上的一种新型的元启发式算法。该算法旨在解决复杂工程优化问题&#xff0c;特别是…

2024-11-15 Java开发工程师 内推

Java开发工程师 坐标&#xff1a;大连 岗位要求&#xff1a; 1、本科以上学历&#xff0c;计算机相关专业 2、22/23/24届毕业生 小结&#xff1a;有意向的私信发简历

Python绘制雪花

文章目录 系列目录写在前面技术需求完整代码代码分析1. 代码初始化部分分析2. 雪花绘制核心逻辑分析3. 窗口保持部分分析4. 美学与几何特点总结 写在后面 系列目录 序号直达链接爱心系列1Python制作一个无法拒绝的表白界面2Python满屏飘字表白代码3Python无限弹窗满屏表白代码4…

当 docker-compose.yaml 文件部署时,Dify 线上版本升级过程

如果线上 Dify 是通过 docker-compose.yaml 文件部署的&#xff0c;那么当 Dify 版本升级时该如何操作呢&#xff1f;官方已经给出了 Docker compose 和 Source Code 两种方式。相对而言&#xff0c;前者更简单些&#xff0c;至少不需要安装依赖包和迁移数据库文件。为了更加具…

RHCSA学习超详细知识点2命令篇

输入命令行的语法 终端中执行命令需要遵照一定的语法&#xff0c;输入命令的格式如下&#xff1a; 命令 参数命令 -选项 参数 输入命令时可以包含多个选项&#xff0c;假如一个命令有-a,-b,-c,-d四个选项&#xff0c;可以写作 命令 -a -b -c -d 参数 这里的多个选项可以“提…

小米路由器用外网域名访问管理界面

本文在Redmi AX3000 (RA81)设置&#xff0c;其他型号路由器的管理界面端口可能各不相同。 开始之前需要保证路由器SSH功能正常&#xff0c;如果没有SSH可以参考这里。 1. 给WAN口开放80端口 可以通过下载mixbox的firewall插件或者其他防火墙插件开放端口。 2. 把域名解析到路…

✅DAY27贪心算法 | 455.分发饼干 | 376. 摆动序列 | 53. 最大子序和

一、贪心算法 核心理念是每一步都做出局部最优选择&#xff0c;以期最终得到全局最优解。它通常用于求解一些最优化问题&#xff0c;例如最小生成树、最短路径、背包问题等。 二、贪心算法的步骤 1. 定义选择标准&#xff1a;确定每一步如何选择当前最优解。 2. 验证贪心策…

无人机+无人车+机器狗:城市巷战突破技术详解

在城市巷战中&#xff0c;无人机、无人车和机器狗的组合可以形成一种全新的战场突破技术&#xff0c;这种组合能够大幅提升作战效率&#xff0c;减少人员伤亡。以下是对这一技术的详细解析&#xff1a; 一、无人机的作用 1.空中侦察&#xff1a;无人机能够提供高空视角&#x…