一文搞懂系列——动态库的加载方式及应用场景

引文

        我们在工作中经常会遇到动态库链接的问题,因为正常的方式并不能满足我们的场景。常见的问题可以总结如下:

  • 系统路径默认路径、usr/lib、/lib 目录,不会集成第三方动态库。
  • 同名动态库可能在多个路径中存在。

        针对不同的场景,根据链接器的加载逻辑,进行相应的处理。

程序的加载流程

        根据专栏《程序员的自我修养》中的【程序员的自我修养02】初识ELF文件格式-CSDN博客可知,可执行文件的运行流程简述如下:

  1. 操作系统加载ELF的文件头。以检查文件格式、操作权限等属性。
  2. 根据文件头中的段表地址,定位到各个段内容。将各个段映射到虚拟地址中。
  3. 查找依赖的动态库并加载
  4. 进入文件头中的Entry point address。执行业务代码。

        其中链接器查找依赖的动态库并加载,这个流程实质很复杂,后续我会在《程序员的自我修养》专栏中详细介绍。本文我们只关心链接器如何去找动态库

问:链接器如何知道可执行程序依赖哪些动态库呢?

答:ELF文件中有一个段.dynamic。这个段里面保存了动态链接器所需要的基本信息,比如依赖哪些动态库动态链接符号表的位置动态链接重定位表的位置共享对象初始化代码的地址等。我们可以通过readelf -d main命令查看该段内容,如下:

Dynamic section at offset 0xda8 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [liba.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000f (RPATH)              Library rpath: [/home/yihua/]
 0x000000000000000c (INIT)               0x5b8
 0x000000000000000d (FINI)               0x794
 0x0000000000000019 (INIT_ARRAY)         0x200d98
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x200da0
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x298
 0x0000000000000005 (STRTAB)             0x3f0
 0x0000000000000006 (SYMTAB)             0x2d0
 0x000000000000000a (STRSZ)              182 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x200fb8
 0x0000000000000002 (PLTRELSZ)           24 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x5a0
 0x0000000000000007 (RELA)               0x4e0
 0x0000000000000008 (RELASZ)             192 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x0000000000000018 (BIND_NOW)
 0x000000006ffffffb (FLAGS_1)            Flags: NOW PIE
 0x000000006ffffffe (VERNEED)            0x4c0
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x4a6
 0x000000006ffffff9 (RELACOUNT)          3
 0x0000000000000000 (NULL)               0x0

        如上可知:main 可执行程序依赖 两个动态库 liba.solibc.so.6。其中黄色字体0x000000000000000f (RPATH)              Library rpath: [/home/yihua/]表示链接器查找动态库的路径,其优先级最高。需要我们关注。其它的参数暂不考虑。

        查看依赖的动态库还可以通过ldd main命令或objdump -x main | grep NEEDED命令。

知道可执行程序依赖哪些动态库口,动态链接器就需要去找这些动态库,查找的方式主要有以下四种。

  • 程序指定路径:rpath
  • 环境变量:LD_LIBRARY_PATH
  • 动态链接器配置文件:/etc/ld.so.conf
  • 系统默认路径:/lib 、 /usr/lib

        其动态链接器加载的顺序分别是rpath --> LD_LIBRARY_PATH -->  /etc/ld.so.conf  --> /lib 、 /usr/lib。

知道四个方式后,我们尝试了解如何使用。本文的示例代码如下:

//a.c
#include<stdio.h>
int a()
{
        printf("i'm liba.a\n");
}
// main.c
#include<stdlib.h>
#include<stdio.h>
extern int a();
int main()
{
        a();
        return 0;
}

编译:

C
yihua@ubuntu:~/test/dynamic$ gcc -FPIC -shared -o liba.so a.c
yihua@ubuntu:~/test/dynamic$ gcc main.c -o main -L. -la

集成:分别将 main 和 liba.so 放入到bin 和lib目录下。

Shell
yihua@ubuntu:~/test/dynamic$ tree
.
├── a.c
├── bin
│   └── main
├── lib
│   └── liba.so
└── main.c

运行:

Shell
yihua@ubuntu:~/test/dynamic$ ./bin/main
./bin/main: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory

如上错误,是因为动态链接器没有找到liba.so导致的。可通过以下四种方式修复。

-Wl,-rpath

        该方式是通过在编译阶段,修改main 可执行程序中的dynamic段达到目的。可查看当前main的dynamic段内容:

        是没有RPATH参数的。可通过如下编译命令:

yihua@ubuntu:~/test/dynamic$ gcc -FPIC -shared -o liba.so a.c
yihua@ubuntu:~/test/dynamic$ gcc main.c -o main -L. -la -Wl,-rpath=/home/yihua/test/dynamic/lib

再查看dynamic段内容:

运行:

拓展:

        -Wl,-rpath是编译阶段修改可执行程序的rpath参数,但是往往我们在工程中是不太确认最终的集成路径的。可以在集成时,采用chrpath命令,修改可执行程序的rpath参数。如下:

yihua@ubuntu:~/test/dynamic$ chrpath -r ./lib/ bin/main    //修改rpath
bin/main: RPATH=/home/yihua/
bin/main: new RPATH: ./lib/
yihua@ubuntu:~/test/dynamic$ chrpath -l bin/main   //查看rpath
bin/main: RPATH=./lib/

完结撒花~~~

LD_LIBRARY_PATH

        环境变量LD_LIBRARY_PATH是我们最最常用的方式,大部分情况下,我们使用该方式即可。使用方式如下:

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/yihua//test/dynamic/lib。编译如下:

yihua@ubuntu:~/test/dynamic$ gcc -FPIC -shared -o liba.so a.c
yihua@ubuntu:~/test/dynamic$ gcc main.c -o main -L. -la

集成:分别将 main 和 liba.so 放入到bin 和lib目录下。

运行:

完结撒花~~~

/etc/ld.so.conf

        该配置文件是系统动态链接器加载的配置文件。我们可以重新创建一个窗口(目的是关闭上述的LD_LIBRARY_PATH环境变量)。修改/etc/ld.so.conf文件,如下:

运行:

        发现依然没有找到动态库,这是为什么呢?我们可以通过strace ./bin/main命令查看程序的加载流程。输出如下:

yihua@ubuntu:~/test/dynamic$ strace ./bin/main
execve("./bin/main", ["./bin/main"], 0x7ffdfd030ae0 /* 26 vars */) = 0
brk(NULL)                               = 0x5643c65c3000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=104673, ...}) = 0
mmap(NULL, 104673, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff91b2ed000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/tls/haswell/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/haswell/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/tls/haswell/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/haswell", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/tls/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/tls/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/tls", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/haswell/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/haswell/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/haswell/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/haswell", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=16384, ...}) = 0
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/tls/haswell/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/haswell/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/tls/haswell/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/haswell", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/tls/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/tls/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/tls", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/haswell/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/haswell/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/haswell/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/haswell", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64-linux-gnu", {st_mode=S_IFDIR|0755, st_size=81920, ...}) = 0
openat(AT_FDCWD, "/lib/tls/haswell/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls/haswell/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/tls/haswell/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls/haswell", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/tls/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/tls/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/tls", 0x7fffcd77f4e0)        = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/haswell/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/haswell/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/haswell/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/haswell", 0x7fffcd77f4e0)    = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib/x86_64", 0x7fffcd77f4e0)     = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
openat(AT_FDCWD, "/usr/lib/tls/haswell/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/haswell/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/haswell/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/haswell", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/tls/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/tls", 0x7fffcd77f4e0)    = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/haswell/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/haswell/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/haswell/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/haswell", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib/x86_64", 0x7fffcd77f4e0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/liba.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/usr/lib", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
writev(2, [{iov_base="./bin/main", iov_len=10}, {iov_base=": ", iov_len=2}, {iov_base="error while loading shared libra"..., iov_len=36}, {iov_base=": ", iov_len=2}, {iov_base="liba.so", iov_len=7}, {iov_base=": ", iov_len=2}, {iov_base="cannot open shared object file", iov_len=30}, {iov_base=": ", iov_len=2}, {iov_base="No such file or directory", iov_len=25}, {iov_base="\n", iov_len=1}], 10./bin/main: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory
) = 117
exit_group(127)                         = ?
+++ exited with 127 +++

        我们从输出结果,可以知道,动态链接器只加载/etc/ld.so.cache配置文件,并没有加载/etc/ld.so.conf配置文件。因此,我们需要通过ldconfig命令更新ld.so.cache文件内容。

如下:

完结撒花~~~

系统默认路径

        系统默认路径即系统存放动态库的地方,一般为/lib、/usr/lib。我们只需要将动态库放到对应的路径下即可。

        重新打开一个窗口,执行如下命令运行:

        完结撒花~~~

总结

        综上所述,我们知道了动态链接库寻找动态库的四种方式,其中:

        系统默认路径和/etc/ld.so.conf需要系统权限,大部分情况是不能进行修改的。若有相应权限,可以优先使用该方式。

        环境变量LD_LIBRARY_PATH可以解决我们大部分场景,比如引文中的第一个场景。但是它并不解决动态库重名的问题。比如引文中的第二个场景。这时,我们就可以采用-Wl,-rpath 编译选项或chrpath修改可执行程序的rpath参数。

        希望本文能够对您有所帮助,还请三连表示支持哦~~~

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

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

相关文章

探索元宇宙链游戏:一场数字世界的奇妙融合

随着互联网的飞速发展&#xff0c;以及人们不断对互动娱乐体验的要求提高&#xff0c;元宇宙渐渐成为人们追求的目标。 而区块链技术的出现给元宇宙链游开发带来了新的机遇和挑战。 一、元宇宙链游定义 元宇宙链游全称为基于区块链技术的元宇宙游戏&#xff0c;是一种新型的网…

ArkTS-列表选择弹窗

调用 每一个sheet中的action对应其点击事件 Button(列表选择弹窗).onClick(() > {ActionSheet.show({title: 列表选择弹窗标题,message: 内容,autoCancel: true,confirm: {value: 确认,action: () > {console.log(Get Alert Dialog handled)}},cancel: () > {console.…

预约按摩小程序有哪些功能特点?

随着科技的飞速发展&#xff0c;我们的生活方式发生了翻天覆地的变化。现在&#xff0c;只需动动手指&#xff0c;就能解决许多生活中的问题。同城预约上门按摩小程序&#xff0c;就是这样一个方便、快捷的解决方案。 在忙碌的生活中&#xff0c;身心疲惫的人们急需一种快速有效…

揭秘强化学习:Python 实践指南

一、说明 强化学习 (RL) 是机器学习和人工智能 (AI) 的一个子领域&#xff0c;专注于开发能够通过与环境交互进行学习的智能代理。与传统的监督和无监督学习不同&#xff0c;强化学习主要关注动态、顺序环境中的决策。它在人工智能中具有重要意义&#xff0c;特别是在自主代理必…

YOLOv8独家原创改进:创新自研CPMS注意力,多尺度通道注意力具+多尺度深度可分离卷积空间注意力,全面升级CBAM

💡💡💡本文自研创新改进:自研CPMS, 多尺度通道注意力具+多尺度深度可分离卷积空间注意力,全面升级CBAM 1)作为注意力CPMS使用; 推荐指数:五星 CPMS | 亲测在多个数据集能够实现涨点,对标CBAM。 收录 YOLOv8原创自研 https://blog.csdn.net/m0_63774211/ca…

单个 Zip 文件体积超过 40GB

单个 Zip 文件体积超过 40GB WinRAR 平时用的多,不过有时候为了更好的通用性,也常常用到 zip 格式.查了一下资料,说是 zip 单个文件的体积不能超过 4GB. 自己动手试了下,用 WinRAR 创建出来的 zip 文件,大小可以超过 40GB, 如下图 为了压缩速度快,压缩方式用的是 “存储” Wi…

动能资讯 | 智能音箱—万物物联新纽带

音箱市场在过去几年经历了显着的增长&#xff0c;这主要得益于数字音乐的普及和技术创新的推动。随着语音助手技术的发展&#xff0c;智能音箱如Amazon Echo、Google Home、Apple HomePod等逐渐成为市场中的热点。这些音箱不仅提供音频播放功能&#xff0c;还整合了语音识别和智…

ACM32F070 RTC 引脚做普通 GPIO 用法配置

有场景需要把带RTC引脚功能的IO当做普通的GPIO使用&#xff0c;但是按照正常的GPIO初始化却无法使用&#xff0c;该芯片手册中有给出介绍 现给出配置方法&#xff0c;参考官方SDK里面PC13的配置&#xff1a; // PC13 GPIOC_Handle.Pin GPIO_PIN_13; GPIOC_Handle.Mod…

pngPackerGUI_V2.0是什么软件?png图片打包plist工具

png图片打包plist工具&#xff0c;手把手教你使用pngPackerGUI_V2.0 此软件是在pngpacker_V1.1软件基础之后&#xff0c;开发的界面化操作软件&#xff0c;方便不太懂命令行的小白快捷上手使用。1.下载并解压缩软件&#xff0c;得到如下目录&#xff0c;双击打开 pngPackerGUI.…

Python基础学习

基础语法 字面量 什么是字面量&#xff1a; 在代码中&#xff0c;被写下来的固定的值&#xff0c;称为字面量 | 类型 | 描述 | 说明 | | — | — | — | | 数组&#xff08;Number&#xff09; | 整数 int | 整数 | | | 浮点型 float | 浮点数 | | | 复数 complex | 复数 如 …

拼多多赚钱更难,利润率持续下滑

国内的电商圈又一次见证历史。 11月29日&#xff0c;拼多多盘中涨超4%&#xff0c;市值到达1924亿美元&#xff0c;首次超过阿里巴巴&#xff0c;成为美股市值最大中概股。 前一日&#xff0c;拼多多(NASDAQ:PDD)公布了2023年三季报&#xff0c;尽管营收和净利润双增&#xf…

前缀和例题:子矩阵的和AcWing796

//前缀和模板提,在读入数据的时候就可以先算好前缀和的大小 //计算前缀的时候用:g[i][j] g[i][j-1] g[i-1][j] - g[i-1][j-1] Integer.parseInt(init[j-1]); //计算结果的时候用:g[x2][y2] - g[x1 - 1][y2]- g[x2][y1-1] g[x1 -1][y1 - 1] "\n" //一些重复加的地…

固态硬盘与机械硬盘的区别

盘、磁道、扇区、柱面&#xff0c;这些都是机械硬盘的概念&#xff0c;固态硬盘没有这些东西&#xff0c;固态硬盘和机械硬盘虽然都叫硬盘&#xff0c;但是在原理层面有着本质上的区别。 速印机&#xff08;理想、荣大等&#xff09;、复印机&#xff08;夏普、东芝、理光、佳能…

Go 语言中的函数调用。

更好的观看体验&#xff0c;请点击——函数调用 | YinKais Blog 本文将从函数的调用惯例和参数传递方法两个方面分别介绍函数执行的过程。 1、调用惯例 对于不同的编程语言&#xff0c; 它们在调用函数的时候往往都使用相同的语法&#xff1a; somefunction(arg0, arg1) 虽…

Intellij idea 快速定位到文件的开头或者结尾的几种方式

方式一&#xff1a;Scroll To Top / Scroll To Bottom 首先打开Keymap设置&#xff0c;并搜索Scroll To 依次点击File->Settings->Keymap可打开该界面 对于Scroll To Top 快速滑动定位到文件顶部&#xff0c; Scroll To Bottom快速定位到文件底部 默认是没有设置快捷键的…

C++ Easyx 让圆球跟随鼠标移动

目录 下载Easyx 检验 绘制窗口 画圆 响应事件的处理 清除原先绘图 渲染缓冲区 逻辑 代码托管 下载Easyx 在Easyx官网下载大暑版: 检验 写如下代码: 编译运行&#xff0c;如果控制台出现2023字样&#xff0c;代表配置成功: 绘制窗口 进入Eaxy官方网站&#xff0c;点…

科研试剂实验室Tubulysin M微管蛋白抑制剂936691-46-2

Tubulysin M 微管蛋白抑制剂 M 936691-46-2 英文名称&#xff1a;Tubulysin M 中文名称&#xff1a;微管蛋白抑制剂 M 化学名称&#xff1a;(2S,4R)-4-[[2-[(1R,3R)-1-乙酰氧基-4-甲基-3-[甲基-[(2S,3S)-3-甲基-2-[[(2R) -1-甲基哌啶-2-羰基]氨基]戊酰基]氨基]戊基]-1,3-噻唑…

数据结构树,二叉树,堆

目录 ​编辑 1.树概念及结构 2. 树的表示 3.二叉树概念及结构 特殊的二叉树 二叉树的性质 ​编辑 二叉树选择题 二叉树的存储结构 4.堆的概念及结构 父亲孩子下标关系​编辑 堆的实现接口 堆结构体设计堆的初始化堆的销毁 堆的插入(附&#xff1a;向上调整算法) 堆…

spring日志输出到elasticsearch

1.maven <!--日志elasticsearch--><dependency><groupId>com.agido</groupId><artifactId>logback-elasticsearch-appender</artifactId><version>3.0.8</version></dependency><dependency><groupId>net.l…