Linux:基础IO(三.软硬链接、动态库和静态库、动精态库的制作和加载)

news2024/11/18 10:57:18

上次介绍了基础IO(二):Linux:基础IO(二.缓冲区、模拟一下缓冲区、详细讲解文件系统)


文章目录

  • 1.软硬链接
    • 1.1硬链接
    • 1.2软链接
    • 使用场景
  • 2.动态库和静态库
    • 1.1回顾
    • 1.2静态库的制作和使用
      • 为什么要有库
      • 制作者角度
        • ar指令—提取静态库文件
        • gcc -l -L 来使用自己的静态库
    • 1.3动态库制作和使用
      • 形成`.o`文件与生成共享库
      • 使用makefile文件整合操作
      • 开始使用库
    • 1.4完善动态库过程
      • gcc -I
      • 拷贝文件简化选项
      • 解决运行找不到问题
  • 3.理解动态库的加载
    • 3.1系统角度
    • 3.2编址
    • 3.3一般程序的加载
    • 3.4动态库的加载


1.软硬链接

1.1硬链接

硬链接(Hard Link)是Linux系统中的一种文件链接方式,它允许多个文件名指向同一个inode(索引节点),从而实现多个文件名指向同一个物理文件数据块

  • 硬链接与原始文件之间没有任何区别,它们共享相同的inode和数据块,因此对任意一个文件的修改都会影响其他所有硬链接指向的文件。
  • 当您修改目标文件时,硬链接也会反映这些修改,因为它们实际上指向同一个数据块。同样,删除硬链接并不会影响目标文件的数据,只是删除了硬链接与inode号的映射关系
  • 硬链接本质上是一个新的文件名,它与目标文件具有相同的inode编号,这种关系可以理解为新的文件名与目标文件的inode号之间的映射关系
  • 硬链接本质就是在指定的目录下,插入新的文件名和目标文件的映射关系,并让inode的引用计数++

创建硬链接:要创建硬链接,可以使用ln命令,语法如下:

ln <target> <link_name>
  • <target>是要创建硬链接指向的目标文件的路径。
  • <link_name>是要创建的硬链接的名称。

file31

上面的那个数字是:硬链接数

  1. 文件的硬链接数是指指向该文件的硬链接的数量。每个文件都会有一个链接计数(link count),用来记录指向该文件的硬链接数量。

当创建一个文件时,该文件的链接计数会初始化为1。当创建一个硬链接时,系统会增加该文件的链接计数。当删除一个硬链接时,系统会减少该文件的链接计数。只有当文件的链接计数减少到0时,系统才会真正删除该文件的数据块,并释放文件占用的空间。

  1. 我们知道文件都有一个与之相关联的inode结构体,inode中包含了文件的元数据信息,例如文件类型、大小、权限等,同时也包含了一个引用计数(reference count)字段

引用计数记录了指向该inode的硬链接数量,也就是指向该文件的硬链接数。当创建一个硬链接时,系统会增加该文件对应inode的引用计数;当删除一个硬链接时,系统会减少该文件对应inode的引用计数

当文件的引用计数减少到0时,系统会执行以下操作:

  1. 将文件的inode标记为未使用,即将inode所在的数据结构标记为可重用。
  2. 将文件数据块的位图标记为未使用,表示这些数据块可以被其他文件使用。
  3. 将文件数据块内容清空,但并不立即释放磁盘空间,而是保留这些数据块的位置信息,以便之后写入新的数据时可以直接覆盖这些块,避免频繁的磁盘写入操作,提高性能。

这种方式称为延迟释放(delayed freeing)

1.2软链接

软链接(Symbolic Link)是Linux系统中用于创建文件链接的一种方式。它是一个特殊类型的文件,其中包含指向另一个文件或目录的路径。软链接与硬链接不同,软链接与原始文件之间是独立的,它们有不同的inode编号。

  • 软链接(符号链接)是一个独立的文件,其中存储着指向目标文件的路径信息
  • 当系统访问软链接文件时,实际上会根据软链接文件中存储的路径信息找到目标文件。软链接文件类似于Windows下的快捷方式,它提供了一种间接引用目标文件的方式

创建软链接:要创建软链接,可以使用ln -s命令,lnLink的缩写,-s代表soft

ln -s <target> <link_name>
  • <target>是要创建软链接指向的目标文件或目录的路径。
  • <link_name>是要创建的软链接的名称。

file32

使用场景

  1. 软链接:软链接本身并不包含可执行代码,而是指向其他文件的路径。如果指向的文件是一个可执行文件,并且符号链接本身具有执行权限,那么可以通过符号链接执行目标文件。

可以在当前路径下建立一个软链接指向较深出的文件。方便我们快速找到

通过在当前路径下创建一个软链接,可以方便地访问位于其他较深路径的文件。这样可以简化文件路径的输入,提高操作效率,同时也可以避免频繁切换目录。

假设您经常需要访问一个深层次的文件/path/to/deep/file.txt,可以在当前路径下创建一个软链接,比如ln -s /path/to/deep/file.txt shortcut.txt,这样您只需要在当前路径下使用./shortcut.txt就可以访问目标文件了。

软链接的特性使得它可以指向任意路径下的文件,包括目录。这种灵活性使得软链接成为管理文件系统中复杂结构的有用工具,提高了文件系统的可访问性和可操作性。

  1. 硬链接:一个目录下有多少个目录可以通过当前目录的硬链接个数减2

file33

Linux中,不能给目录建立硬链接!
因为环路问题不允许给目录建立硬链接!
除非系统自己给目录建立硬链接:...


2.动态库和静态库

1.1回顾

file34

ldd是一个Linux命令,用于打印出一个可执行文件或共享库的动态链接依赖关系。通过运行ldd命令,您可以查看一个可执行文件或共享库所依赖的其他库文件,以及这些库文件的路径。

使用ldd命令的基本语法:

ldd <executable_file>

<executable_file>是您要查看动态链接依赖关系的可执行文件的路径。

  1. 为什么需要库?
    • 库是预先编译的可重用代码的集合,用于提供常用功能和服务。通过使用库,开发人员可以避免重复编写相同的代码,提高代码重用性和开发效率。此外,库还可帮助开发人员处理系统差异性,使得程序在不同系统上能够正确运行。
  2. 有哪些类型的库?
    • 库分为动态库和静态库两种类型。动态库(Dynamic Link Libraries)在程序运行时加载到内存中,而静态库(Static Libraries)在编译时被链接到可执行文件中。在云服务器中,默认安装的是动态库。
    • 云服务器是默认安装动态库的,没有安装静态库
  3. 如何查询程序的依赖关系?
    • 使用ldd命令可以查询一个可执行文件所依赖的动态链接库。
  4. 什么是静态链接?
    • 静态链接是将库的代码和数据在编译时直接复制到可执行文件中的链接方式。通过在编译时静态链接库,可生成一个独立于系统环境的可执行文件。
  5. 默认编译程序时,使用的是动态编译。如果想要使用静态编译,需要加上-static选项
  6. 库的命名规则:
    • 动态库通常以libXXX.so的形式命名,而静态库通常以libXXX.a的形式命名
    • 在库的真实名称中,通常会去除lib前缀和.so.a后缀,只保留名称部分。剩下的就是真实名称

1.2静态库的制作和使用

为什么要有库

  1. 提高代码的重用性和开发效率:库中包含了经过封装和优化的代码片段,可以提供常用功能和服务。通过使用库,开发人员可以避免重复编写相同的代码,提高代码的重用性和开发效率。
  2. 隐藏源代码
  3. 简化开发:库提供了现成的解决方案和功能模块,可以帮助开发人员快速构建应用程序,减少开发时间和工作量。
  4. 提高可靠性:经过广泛测试和验证的库通常具有较高的可靠性和稳定性,可以减少程序中的错误和bug,提高程序的质量。
  5. 处理系统差异性:不同操作系统和平台之间存在差异,库可以帮助开发人员处理这些差异性,使得程序能够在不同系统上正确运行。
  6. 提供标准接口:库通常提供了标准化的接口和API,开发人员可以通过这些接口与库进行交互,而不必关心底层实现细节。

制作者角度

file35

这里我们写好了4个文件,分别是mymath.cmymath.hmystdio.cmystdio.h

使用:gcc -c

用于将源代码编译为目标文件(object file)。目标文件包含了机器代码,但它还不是一个完整的可执行程序,因为它还缺少一些信息,如启动代码、库函数的链接等。

-c 选项告诉 GCC 只进行编译阶段,不进行链接阶段。这样,你可以得到 .o(object file)后缀的目标文件,而不是可执行文件。而且文件默认生成的名字与源文件相同,改下后缀

file36

我们把二者进行打包,传给user(给这个user使用)

ar指令—提取静态库文件

ar命令是一个用于创建、修改和提取静态库文件的工具。静态库是编译后的程序代码集合,包含一组函数或其他对象文件,可以在链接时与可执行文件一起使用。通过将多个目标文件合并到一个静态库中,可以将其作为单个实体进行管理和分发,有助于减小可执行文件的大小和编译时间。

ar命令的基本语法如下:ar [参数选项] [归档文件名] [目标文件列表]

  • c:创建归档文件。
  • r:向归档文件中添加目标文件。
  • d:从归档文件中删除目标文件。
  • t:列出归档文件中包含的目标文件列表。
  • x:从归档文件中提取目标文件。
  • a:在库的一个已经存在的成员后面增加一个新的文件。
  • b:在库的一个已经存在的成员前面增加一个新的文件。
  • m:移动成员在库中的位置。
  • u:替换或更新库中的成员。
  • v:显示操作过程。
ar -rc libmyc.a *.o

file37

file38

写一份测试代码来使用一下这个库

#include "mymath.h"
#include "mystdio.h"
#include <stdio.h>

int main()
{
    int res = myAdd(10, 20);

    printf("%d+%d=%d\n", 10, 20, res);
    
    myFILE *fp = my_fopen("log.txt", "w");
    if(fp == NULL) return 1;
    return 0;
}
gcc -l -L 来使用自己的静态库

在GCC编译器中,-l选项用于链接库文件。它后面跟着要链接的库的名称,不包括前缀“lib”和扩展名。例如,如果想链接一个名为libmath.so的数学库,可以使用-lmath选项。GCC会在默认的库路径中搜索该库,并将其链接到生成的可执行文件中。

此外,-l选项仅仅告诉GCC在链接阶段使用哪个库,但它并不指定库文件的搜索路径。

如果需要指定库文件的搜索路径,可以使用-L选项。例如,-L/path/to/library将告诉GCC在/path/to/library目录下搜索库文件。

file39

1.3动态库制作和使用

形成.o文件与生成共享库

上面我讲解了,静态库的制作和使用,我们在形成.o文件时,都是使用gcc -c code.c ==> code.o。我们在打包时也是使用功能ar

现在我们使用:

  1. shared:
    当我们在编译或链接一个库时,我们通常会指定它应该是一个共享库。这意味着该库的文件格式是为了与其他程序共享而设计的。在GCC或其他类似的编译器中,通常使用-shared选项来指示应该生成一个共享库。(共享库就是动态链接库)
  2. fPIC (Position Independent Code):
    位置无关代码(PIC)是一种代码类型,它不依赖于它在内存中的具体地址来运行。这是共享库所需要的,因为共享库可以在程序的运行时被加载到任何内存地址。使用-fPIC选项(在GCC中)告诉编译器生成这样的代码(产生与位置无关码)。
  3. 库名规则:libxxx.so:
    在Linux系统中,共享库通常遵循特定的命名约定。它们通常以lib开头,后跟库的名字(例如xxx),并以.so结尾。这里的.so代表“shared object”,即共享对象

为了创建一个名为libmyc.so的共享库,使用如下的命令:

gcc -shared -fPIC -o libmyc.so *.o

file310

使用makefile文件整合操作

makefile文件内容如下

libmyc.so:mymath.o mystdio.o
	gcc -shared -o $@ $^
mymath.o:mymath.c
	gcc -c -fPIC  $<
mystdio.o:mystdio.c
	gcc -c -fPIC $<

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

过程与细节:

  1. 首先,Make 工具会查找当前目录下的 Makefile 文件,并读取其中的规则和指令。
  2. Make 工具会检查每个规则中的目标文件(target)和依赖文件(prerequisites)的时间戳,以确定哪些文件需要重新生成。
  3. 如果某个目标文件不存在,或者某个依赖文件的时间戳比目标文件的时间戳更新,那么 Make 工具会执行该规则中定义的命令来生成目标文件。
  4. 对于上述的 Makefile 文件,首先会检查 libmyc.so 文件是否存在,以及其依赖文件 mymath.omystdio.o 的时间戳情况。
  5. 使用 make 指令时,Makefile 会按照默认规则执行第一个目标(在这里是 libmyc.so),并且只会执行第一个目标所依赖的规则。在这个例子中,libmyc.so 依赖于 mymath.omystdio.o因此会执行这两个规则来生成对应的目标文件
  • 在 Makefile 中,$< 是一个自动变量,用于表示当前规则中的第一个依赖文件(prerequisite)。当 Make 工具执行规则时,$< 会被替换为当前规则中的第一个依赖文件的文件名。

  • 使用 $^ 会将所有的依赖文件传递给命令,而使用 $< 只会传递当前规则中的第一个依赖文件。如果有多个依赖文件,$< 会在每个依赖文件上执行一次。

  • 因此,在 Makefile 中,如果有多个依赖文件,并且在命令中使用了 $<,那么命令会在每个依赖文件上执行一次。

也能写成这样:

libmyc.so:mymath.o mystdio.o
	gcc -shared -o $@ $^
%.o:%.c
	gcc -c -fPIC  $<

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

%.o: %.c

这个规则是一个模式规则(pattern rule),表示所有以 .o 结尾的目标文件依赖于对应的 .c 源文件。在生成目标文件的命令中,使用了 $<$< 表示当前规则中的第一个依赖文件,即对应的 .c 源文件。因此,命令 gcc -c -fPIC $< 会将对应的 .c 源文件编译成目标文件。

开始使用库

首先把.h文件交给使用者

cp ./*.h user

在这里插入图片描述

1.4完善动态库过程

首先我们完善一下makefile文件,添加能生成一个压缩包,里面分有include目录和lib目录,分别放有头文件和库

libmyc.so:mymath.o mystdio.o
	gcc -shared -o $@ $^
mymath.o:mymath.c
	gcc -c -fPIC  $<
mystdio.o:mystdio.c
	gcc -c -fPIC $<

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

.PHONY:output
output:
	mkdir -p mylib/include
	mkdir -p mylib/lib
	cp -rf *.h mylib/include
	cp -rf *.so mylib/lib
	tar czf mylib.tgz mylib

使用make output后,就能生成满足要求的压缩包

file312

file313

现在,如果直接进行编译会报错

file314

gcc -I

在使用 gcc 编译器时,-I 选项用于指定头文件的搜索路径(在展开头文件时)。头文件通常包含在 #include 指令中,用于引入外部库或自定义的头文件。告诉编译器,可以在-1指定的路径下进行搜索头文件

gcc -I <include_path>

其中 <include_path> 是指定的头文件搜索路径。您可以在 -I 后面指定多个路径,用冒号或空格分隔。

现在要使用

gcc -I ./mylib/include -lmyc -L ./mylib/lib/libmyc.so main.c
  1. -I ./mylib/include:这个选项告诉编译器在 ./mylib/include 目录中查找头文件。在编译过程中,编译器会在指定的路径中搜索您在源代码中包含的头文件。

  2. -lmyc:这个选项告诉编译器链接名为 libmyc.so 的库文件。通常,-l 选项后面跟着的是库文件的名称,编译器会在指定的库路径中查找该库文件。

  3. -L ./mylib/lib:这个选项告诉编译器在 ./mylib/lib 目录中查找库文件。编译器会在指定的路径中搜索您指定的库文件,以便在链接阶段正确地链接库文件。

file315

拷贝文件简化选项

所谓的把库(其他软件)安装到系统中,本质就是把对应的文件,拷贝到系统指定的路径中(机器规定好的,一般都是root的目录)

所以经常需要我们普通用户使用sudo

我们可以把自己的头文件与库分别拷贝到系统头文件目录下和库目录下

sudo mylib/include/* /usr/include

sudo mylib/lib/libmyc.so /lib64

这样后直接使用

gcc -lmyc main.c

就能实现编译链接

还是不建议大家把自己写的不是很成熟的代码,放到系统库里

解决运行找不到问题

file316

链接生成可执行程序后,但在执行可执行文件时出现 “not found” 错误,通常是由于系统无法找到所需的动态库文件导致的。这种情况通常发生在链接的是动态库,并且操作系统无法实时找到该动态库的情况下。(所以对于动态库,编译器要能找到,OS也要能找到

解决这个问题的方法可以采用以下几种方式:

  1. 默认路径拷贝

    • 将头文件(.h 文件)和动态库文件(.so 文件)拷贝到系统默认路径,如 /usr/include/lib/ 目录中。
  2. 增加LD_LIBRARY_PATH环境变量

    • 使用环境变量 LD_LIBRARY_PATH 来指定动态库的路径:系统运行程序时,动态库查找的辅助路径

    • 没有的话可以通过以下命令设置:

      export LD_LIBRARY_PATH=/path/to/your/library:$LD_LIBRARY_PATH
      
    • 本身就有的话,使用以下命令把自己的库的绝对路径添加到LD_LIBRARY_PATH里面

      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:自己库的绝对路径
      
      1. $LD_LIBRARY_PATH:在 Shell 脚本或命令中,$LD_LIBRARY_PATH 表示引用环境变量 LD_LIBRARY_PATH 的值。使用 $ 符号可以获取环境变量的值,而不是直接使用变量名。因此,$LD_LIBRARY_PATH 将会被替换为 LD_LIBRARY_PATH 环境变量的当前值。

      2. LD_LIBRARY_PATHLD_LIBRARY_PATH 是一个环境变量,用于指定动态链接库(共享库)的搜索路径。通过设置 LD_LIBRARY_PATH 环境变量,您可以告诉系统在哪些路径中查找动态链接库。这个环境变量在编译和运行需要动态链接库的程序时非常有用。

  3. 使用软连接

    • 使用 ln -s 命令创建动态库文件的软链接到系统默认搜索路径中,例如:

      sudo ln -s /path/to/my/libmyc.so /lib64/libmyc.so
      
    • 这样可以在默认搜索路径中建立软链接,使系统能够找到动态库文件。

  4. 修改配置文件

    • /etc/ld.so.conf.d/ 目录下新建文件,并在文件中加入自定义库的路径
    • 然后运行 sudo ldconfig 命令来更新系统的动态链接库配置,使系统能够实时找到动态库文件。

如果是官方的库的话,我们最好还是直接使用方法一。这样方便我们查找

自己的库的话,使用方法三就行


3.理解动态库的加载

动态库的加载是指在程序运行时,操作系统会将动态库加载到内存中,并将程序与动态库建立链接,以便程序能够调用动态库中的函数和资源。动态库的加载是延迟加载的,即在程序需要调用动态库中的函数时才会加载相应的库。

静态库在编译时会被整合到可执行文件中,因此在程序运行时不需要额外加载库文件。静态库的所有代码和数据都会被复制到可执行文件中,因此程序在运行时可以独立执行,不需要依赖外部的库文件。

总的来说,动态库的加载是指在程序运行时将库文件加载到内存中,并建立链接关系,使得程序能够调用库中的函数和资源。而静态库在编译时已经被整合到可执行文件中,因此在程序运行时不需要加载外部库文件。

动态库、共享库的本质就是:所有系统进程中公共的代码和数据,只需要存在一份!

3.1系统角度

  • 在程序加载时,代码通常被加载到进程的虚拟地址空间中的代码段中。当程序执行到调用库函数的代码时,CPU会跳转到库函数的代码所在的内存地址,并开始执行库函数的代码

  • 在动态库加载之后,动态库的代码和数据会被映射到进程的共享区中,使得进程可以直接访问和调用动态库中的函数和资源

  • 当一个动态库已经加载到物理内存中,已有进程正在使用该库时,如果另一个进程也需要使用同一个动态库,操作系统会采取共享内存的方式,使新的进程的地址空间直接映射到已加载的动态库的内存处

file317

谁来决定那些库加载了,哪些没加载?0S会自动完成

在Linux系统中,决定哪些库会加载,哪些库不会加载的主要责任在于动态链接器(dynamic linker)和运行时链接器(runtime linker)。这两个组件是操作系统的一部分,负责在程序运行时动态加载和链接库文件。

在操作系统中,可以同时存在大量的已加载库,这些库可能是系统自带的标准库、第三方库或用户自定义的库。操作系统需要管理这些库,以确保程序能够正确运行并提供良好的性能。

  • 先描述,再组织

3.2编址

编址是指为内存中的每个存储单元分配一个唯一的地址,以便程序可以准确地访问和操作内存中的数据。在计算机系统中,编址是非常重要的,因为程序需要通过地址来定位和访问内存中的数据和指令。编址的过程涉及到操作系统、编译器以及可执行程序本身的格式信息。

尽管可执行程序还没有被加载到内存中,但它仍然具有地址的概念。在编译过程中,编译器会为程序中的各个变量、函数等符号分配地址,这些地址通常是相对地址或者符号表中的偏移量。这样,即使程序还没有被加载到内存中,各个符号仍然具有自己的地址。

此外,可执行程序在磁盘上已经被划分为不同的区域,这些区域通常包括代码段、数据段、符号表等。这些区域的划分通常是在编译器生成可执行文件时完成的,根据程序的结构和需要,编译器会将程序划分为不同的区域,并为每个区域分配相应的权限和访问属性。

因此,即使可执行程序还没有被加载到内存中,它仍然具有地址的概念,并且已经被划分为不同的区域。这些地址和区域的信息在程序加载到内存时会被操作系统读取,并根据这些信息将程序的各个部分映射到进程的虚拟地址空间中

所以,我们之前讲解的进程地址空间里的虚拟地址,其实是由编译器在编译过程生成的。后来由操作系统读取,成为虚拟地址

编址方式有两个:绝对编址和相对编址/逻辑编址

  • 绝对编址(平坦模式):地址都是连续的
  • 相对编址/逻辑编址:会为每个不同的区域的开始处(start)分配一个地址后,其后地址为相对于start的偏移量(0、1、2····、n)

对于平坦模式Linux在使用,我们能认为可执行程序只有一个区域:地址=start+偏移量(现在start=0,偏移量就是本身的绝对编址)

3.3一般程序的加载

在CPU中,CR3(Control Register 3)是一种控制寄存器,用于存储页目录表的物理地址。在x86架构的处理器中,CR3寄存器用于指示当前进程的页目录表的物理地址,从而实现虚拟内存的地址转换。当处理器需要访问内存时,会使用CR3寄存器中存储的页目录表地址来查找对应的页表,进而将虚拟地址转换为物理地址。

PC指针(Program Counter)是另一个重要的寄存器,用于存储当前正在执行的指令的地址或下一条将要执行的指令的地址。PC指针在程序执行过程中不断更新,指向当前指令或即将执行的下一条指令的地址。处理器根据PC指针中存储的地址来获取下一条指令的内容,并执行相应的操作。

file318

地址空间既然是一个数据结构对象,谁来用什么数据初始化呢?——使用ELF格式的表头信息来进行初始化

  • 在操作系统中,地址空间的初始化通常是由操作系统内核来完成的。当一个进程被创建时,操作系统会负责为该进程分配新的地址空间,并初始化这个地址空间。在这个过程中,操作系统可以使用可执行和可加载文件的头部信息(如ELF格式的表头信息)来进行初始化

  • ELF(Executable and Linkable Format)是一种常见的可执行文件格式,用于存储可执行程序的代码、数据和其他相关信息。ELF文件包含了各种表头信息,用于描述程序的布局、段的位置、大小、权限等信息。操作系统可以解析这些表头信息,根据其中的段表(Section Header Table)和程序头表(Program Header Table)等内容来初始化进程的地址空间。

所谓的地址空间,本质是由操作系统+ 编译器 + 计算机体系结构(CPU)三者共同配合完成

  • OS要能构建进程,进程地址空间,页表等
  • 编译器要能在编译时产生逻辑地址和表头信息,供地址空间与页表的初始化
  • CPU要有相关寄存器:cr3与pc指针等,还要能从虚拟地址转换为物理地址

3.4动态库的加载

file319

动态库库的数据和方法的访问,都是可以通过库在地址空间
起始地址+我们程序内部的偏移量即可


现在IO基础也是全部讲完啦。下面开始进程间通讯了(这周是考试周好累啊)

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

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

相关文章

基于单片机的智能浇花系统设计与实现

摘要: 设计了一种智能湿度感应浇花系统 。 系统以单片机 AT89S52 为控制芯片&#xff0c;利用 SLHT5-1 土壤湿度传感器来检测土壤的相对湿度&#xff0c;再通过单片机进行信息处理&#xff0c;采用模糊控制方法&#xff0c;输出控制信号&#xff0c;控制继电器的动作&…

[RPI4] 树莓派4b安装istoreos及使用 -- 1. 系统安装

最近在研究家庭智能化的一些东西,其中包括网络,智能家居等一系列内容,然后看过的资料有的想再回来看的时候就找不到了,然后就想着开这么一个系列,做一些记录,先从智能家居开始吧。 1 安装istoreos系统 iStoreOS 目标是提供一个人人会用的路由兼轻 NAS 系统,不管是作为路…

MES管理系统中的仓库管理功能有哪些用途

在当今制造业迅猛发展的背景下&#xff0c;企业对于车间生产调度的需求日益迫切。为此&#xff0c;MES管理系统应运而生&#xff0c;它作为一款专注于车间生产调度的管理信息系统&#xff0c;正逐步成为制造业提升生产效率、优化资源配置的利器。特别是其在仓储和物流管理方面的…

算法社区-从零开始构建(一)

好久没动笔了&#xff0c;一是要处理的东西很多&#xff0c;二则写出来未见得深刻&#xff0c;感觉沉淀得不够&#xff0c;太浅显的东西就没必要分享。 正好最近在研究算法层面的东西&#xff0c;感觉挺受用的&#xff0c;就想着把这些东西整理出来&#xff0c;有点像社区的雏形…

NAPI篇【4】——NAPI应用点亮一个LED

OpenHarmony的NAPI功能为开发者提供了JS与C/C不同语言模块之间的相互访问&#xff0c;交互的能力&#xff0c;使得开发者使用C或者C语言实现应用的关键功能。如操作开发板中某个GPIO节点的状态&#xff08;OpenHarmony并没有提供直接操作GPIO口状态的API&#xff09;&#xff0…

Vue-Cli 创建vue2.0 + TypeScript 项目

这里写目录标题 一、创建项目名称二、选择 Manually select features三、勾选配置项四、选择vue版本五、其它配置 一、创建项目名称 vue create 项目名称&#xff08;项目名字不能含义大写字母&#xff09;二、选择 Manually select features &#xff08;按箭头上下进行移动…

万物皆对象,你信吗?

**内存空间和数据都消失&#xff0c;数据怎么会消失的&#xff1f;**空间没了&#xff0c;数据自然也跟着消失。因为数据就是在空间里面的。就像宇宙大爆炸&#xff0c;我们还能存在嘛&#xff0c;是不是已经undefined了。「一块小内存上有2种数据类型」 内部存储的数据 地址值…

使用Fiddler如何创造大量数据

在调试和分析网络流量时&#xff0c;您是否曾为无法深入了解请求和响应的数据而感到困惑&#xff1f;如果有一种工具可以帮助您轻松抓取和分析网络流量&#xff0c;您的工作效率将大大提升。Fiddler正是这样一款功能强大的抓包工具&#xff0c;广受开发者和测试人员的青睐。 Fi…

专业140+总分400+武汉理工大学855信号与系统考研经验电子信息与通信工程,真题,大纲,参考书

专业855信号与系统140&#xff0c;总分400&#xff0c;今年顺利上岸武汉理工大学&#xff0c;总结一下自己的复习经历&#xff0c;希望对报考武理工的同学有所帮助。专业课&#xff1a;855信号与系统 首先教材&#xff1a; 《信号与系统》高等教育出版社 作者&#xff1a;刘泉…

详解三种常用标准化 Batch Norm Layer Norm RMSNorm

参考&#xff1a; BN究竟起了什么作用&#xff1f;一个闭门造车的分析《动手学深度学习》7.5 节 深度学习中&#xff0c;归一化是常用的稳定训练的手段&#xff0c;CV 中常用 Batch Norm&#xff1b; Transformer 类模型中常用 layer norm&#xff0c;而 RMSNorm 是近期很流行…

Pyppeteer原理介绍和入门尝试

pyppeteer仓库地址&#xff1a;https://github.com/miyakogi/pyppeteer puppeteer仓库地址&#xff1a;https://github.com/search?qpuppeteer&typerepositories 因为有些网页是可以检测到是否是使用了selenium。并且selenium所谓的保护机制不允许跨域cookies保存以及登…

JavaScript的学习之事件的简介

目录 一、事件是什么 二、如何处理事件 一、事件是什么 定义&#xff1a;事件就是浏览器和用户之间的交互行为。 例如&#xff1a;点击按钮、鼠标移动、关闭窗口等。 二、如何处理事件 我们可以在对应的事件属性中设置一些JS行为&#xff0c;当事件触发的时候会将这些代码执行…

java的输入流FileInput Stream类

一、定义 使用InputStream类的FileInputStream子类实现文本文件内容的读取。 二、常用构造方法 三、使用FileInput Stream类按多字节读取数据 1.示例 2、分析 四、常见错误 今天的总结就到这里啦&#xff0c;拜拜&#xff01;

Windows操作系统安装mysql数据库(zip安装包)

MySQL是目前最为流行的开放源码的数据库&#xff0c;是完全网络化的跨平台的关系型数据库系统&#xff0c;它是由瑞典MySQLAB公司开发&#xff0c;目前属于Oracle公司。任何人都能从Internet下载MySQL软件&#xff0c;而无需支付任费用&#xff0c;并且“开放源码”意味着任何人…

活动预告|探索 LLM 大模型的小型化 —— 微软 Phi3在 NVIDIA Jetson 与 NIM 平台的最佳实践

在当前高速发展的人工智能领域&#xff0c;如何高效的部署和优化 SLM (小型的大模型) 成为关键。随着微软 Phi-3 系列模型的发布&#xff0c;让 SLM 在 NVIDIA Jetson 边缘计算平台上的部署成为可能。同时 Phi-3 系列模型已在 NVIDIA NIM 平台提供加速的推理服务。 NVIDIA NIM…

msvcp120.dll丢失怎么办,找不到msvcp120.dll的多种解决方法

最近&#xff0c;我在运行一个程序时遇到了一个错误&#xff0c;系统提示找不到msvcp120.dll文件&#xff0c;无法继续执行代码。这让我感到非常困扰&#xff0c;因为这个问题导致我无法正常运行这个程序。经过一番搜索和尝试&#xff0c;我找到了几种修复这个问题的方法&#…

ONLYOFFICE 桌面编辑器 8.1重磅来袭:全新功能提升您的办公效率

文章目录 前言ONLYOFFICE 桌面编辑器8.1一、PDF编辑&#xff1a;告别“头痛”时刻二、幻灯片版式&#xff1a;秒变“设计大师”三、无缝切换&#xff1a;办公界的“快速通道”四、语言支持&#xff1a;全球通吃的“翻译官”五、 隐藏“连接到云”板块&#xff1a;摆脱“云”的束…

RocketMQ如何添加JVM监控

这里是小奏,觉得文章不错可以关注公众号小奏技术 JVM监控选型 本次JVM监控我们采用prometheus官方提供的jmx_exporter来实现 RocketMQJVM开发 整体目录 1. 新增agent目录 我们在distribution目录新增一个agent模块&#xff0c;然后添加两个文件 jmx_prometheus_javaagent-…

Mysql索引底层数据结构——Java全栈知识(28)

Mysql索引底层数据结构 1、什么是索引 索引在项目中还是比较常见的&#xff0c;它是帮助MySQL高效获取数据的数据结构&#xff0c;主要是用来提高数据检索的效率&#xff0c;降低数据库的IO成本&#xff0c;同时通过索引列对数据进行排序&#xff0c;降低数据排序的成本&…

低价可转债崩盘,发生了什么?

下跌不在于“出库”&#xff0c;甚至不在于“风险”。问题更多在于交易层面&#xff0c;何时能积聚更多的左侧资金并成功过渡至右侧。 低价券怎么了&#xff1f; 如果说6月初主要是小微盘品种的退市风险&#xff0c;后来是一些评级下调的品种&#xff0c;到本周&#xff0c;已…