Linux系统:ELF文件的定义与加载以及动静态链接
本节重点
- ELF文件的概念与结构
- 可执行文件,目标文件ELF格式的区别
- ELF文件的形成过程
- ELF文件的加载
- 动态链接与静态链接
- 动态库的编址与方法调用
一、ELF文件的概念与结构
1.1 文件概述
ELF(Executable and Linkable Format)即“可执行与可链接格式”,是类Unix系统(如Linux)中用于存储可执行程序、目标代码、共享库和核心转储的标准二进制文件格式。它替代了早期的a.out和COFF格式,具备更好的可扩展性和灵活性,成为现代Unix-like系统(包括Linux、FreeBSD等)的主流文件格式。
1.2 文件结构
ELF文件由ELF头(ELF Header)、程序头表(Program Header Table)、节头表(Section Header Table)和数据区域四部分组成,各部分通过偏移量和大小关联。
1. ELF Header
位置:文件开头(固定偏移量0x00)。
作用:描述文件的基本属性,包括:
- 文件类型:可执行文件(
ET_EXEC
)、共享库(ET_DYN
)、目标文件(ET_REL
)等。 - 目标机器架构:如x86、ARM等(通过
e_machine
字段标识)。 - 入口地址:可执行文件的起始执行地址(
e_entry
)。 - 程序头表和节头表的位置:通过
e_phoff
和e_shoff
字段指定。
在命令行中我们可以通过如下命令来查看某一可执行文件的ELF Header:
readelf -h 可执行文件的路径
2. 程序头表(Program Header Table)
位置:由ELF头中的e_phoff
字段指定。
作用:定义文件在内存中的布局,用于程序加载。
组成:由多个程序头(Program Header)条目组成,每个条目描述一个段(Segment),包括:
- 段类型:如
PT_LOAD
(可加载段)、PT_DYNAMIC
(动态链接信息)等。 - 虚拟地址:段在内存中的起始地址。
- 文件偏移量:段在文件中的起始位置。
- 段大小:段在文件和内存中的大小。
- 关联的节:通过程序头表的条目,可以间接或直接知道哪些节被合并到该段中。
3. 节头表(Section Header Table)
位置:由ELF头中的e_shoff
字段指定。
作用:描述文件的逻辑结构,用于链接和调试。
组成:由多个节头(Section Header)条目组成,每个条目描述一个节(Section),包括:节名称、节类型、节地址、节偏移量、节大小。
4. 数据区域
内容:实际存储代码、数据、符号表等信息的区域。
布局:由程序头表和节头表共同描述,但数据本身是连续存储的。
在ELF文件中,ELF Header记录了文件的整体信息,其中包含两个关键字段e_phoff和e_shoff,分别指向程序头表(Program Header Table)和节头表(Section Header Table)。程序头表由多个条目组成,每个条目描述一个段的信息;节头表同样由多个条目构成,每个条目对应一个节的信息。节和段是数据组织的两种方式:节主要用于链接和调试时的逻辑划分,段则对应程序加载到内存时的物理单元。
附言:可执行文件ELF格式与目标文件ELF格式的区别与关联
目标文件和可执行文件均采用ELF格式,但目标文件是编译阶段的中间产物,包含未链接的代码和数据;可执行文件是链接阶段的最终产物,包含已链接的代码和数据,可直接加载到内存执行。两者通过链接器关联,目标文件是可执行文件的“零件”,可执行文件是目标文件的“组装成品”。
维度 目标文件(.o) 可执行文件 文件内容 包含未链接的代码、数据、符号表等。 包含已链接的代码、数据、动态链接信息等。 符号表 包含未解析的外部符号引用(如未定义的函数)。 所有符号均已解析,可能包含导出符号(供共享库使用)。 程序头表(PHDR) 无程序头表(或仅部分信息)。 包含完整的程序头表,描述段(Segment)的内存布局。 节头表(SHDR) 包含完整的节头表,描述节(Section)的逻辑布局。 保留节头表,但主要用于调试,程序加载依赖程序头表。 可执行性 不可直接执行。 可直接执行。 动态链接信息 无(或仅部分信息)。 可能包含动态链接信息(如 .dynamic
节)。
二、ELF文件的形成
ELF文件的形成是一个涉及编译、汇编、链接等多个阶段的复杂过程:
2.1 编译与汇编阶段:
首先程序员使用C/C++等高级语言编写源代码,之后通过编译器(如gcc)将源代码翻译成汇编语言代码,生成.i和.s等中间文件。
之后汇编器将汇编语言代码翻译成机器指令,生成目标文件(.o文件)。目标文件是编译后的中间产物(如 gcc -c
生成),其 ELF 格式包含以下关键部分:
-
节(Sections):存储代码、数据、符号表等(如
.text
、.data
、.rodata
、.bss
)。 -
重定位表(Relocation Tables):记录需要后续链接阶段修正的地址(如
.rel.text
、.rel.data
)。 -
符号表(Symbol Table):记录全局符号(函数、变量)的临时地址和属性。
-
节头表(SHDR):包含完整的节头表,描述节(Section)的逻辑布局。
-
程序头表(PHDR):无程序头表(或仅部分信息)。
-
ELF Header:描述文件的基本属性。
之后编译器会对目标文件进行相对编址,其方式会有以下特点:
1> 节地址从零开始
编译器在生成目标文件时,会将每个节(Section)的代码或数据从地址 0 开始布局。例如:
.text
节中的第一条指令的地址是0
,第二条指令的地址是0 + 指令长度
,依此类推。.data
节中的第一个全局变量的地址是0
,第二个变量的地址是0 + 变量大小
。
因为目标文件是未链接的中间产物,编译器无法预知最终内存布局,比如后续链接器会将多个目标文件的节合并,并分配具体的虚拟地址(如 .text
从 0x08048000
开始)。因此,编译器采用“零基地址”作为占位符,后续由链接器通过重定位修正为真实地址。
2> 依赖重定位表修正地址
目标文件中所有需要后续修正的地址(如跨节引用、外部符号)会记录在重定位表中,以便于后续链接阶段链接器进行地址修正。
2.2 链接阶段
步骤1:节合并与段形成
链接器将不同目标文件中的相同类型的节(如.text
、.data
)合并成一个大的节,之后链接器会根据节的属性(如代码、数据、只读/可写)和用途(如执行、存储变量),将相关节合并为段。例如,所有可执行代码的节(如.text
)会被合并为代码段;已初始化数据(.data
)和未初始化数据(.bss
)会被合并为数据段;只读数据(如.rodata
)可能会被合并为只读数据段。
链接器完成节到段的合并后生成一张Section to Segment mapping ,用来表示节与段的映射结果,我们可以通过以下命令来查看:
readelf -l 可执行文件
Section(节)组织成段(Segments)的主要原因是为了减少页面碎片,提高内存使用效率。如果不进行组织, 假设页面大小为4096字节(内存块基本大小,加载,管理的基本单位),如果.text部分为4097字节,.init部分为512字节,那么它们将占用3个页面,而合并后,它们只需2个页面。
步骤2:分配虚拟地址(VMA)
链接器通常采用平坦模式对整个ELF文件进行统一编址,其方法是0.(0地址处)+偏移量:
步骤3:符号解析与重定位
符号解析:链接器检查所有未定义符号(如 printf
)是否在其它目标文件或库中定义。
重定位修正:根据重定位表(.rel.text
、.rel.data
)修正代码和数据中的临时地址。
步骤4:生成可执行文件
链接器将合并后的段和相关的头部信息(如ELF头、程序头表、节头表)写入可执行文件,其中程序头表(PHDR)描述段如何加载到内存。
readelf -l a.out
输出示例:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x00100 0x00100 R E 0x1000
LOAD 0x000100 0x0804a000 0x0804a000 0x00050 0x00060 RW 0x1000
VirtAddr
字段即为链接阶段分配的虚拟地址,用来加载时初始化程序地址空间。
三、ELF文件的加载
3.1 可执行程序的加载
3.1.1 初始化虚拟地址空间
在之前我们知道,程序的虚拟地址空间本质上就是一个结构体mm_struct,其在内核层面的定义如下:
struct mm_struct {struct vm_area_struct *mmap; // 指向VMA链表的头节点pgd_t *pgd; // 页全局目录(PGD,即顶级页表)atomic_t mm_users; // 用户空间引用计数atomic_t mm_count; // 内核空间引用计数unsigned long start_code, end_code; // 代码段起止地址unsigned long start_data, end_data; // 数据段起止地址unsigned long start_brk, brk; // 堆的起止地址unsigned long start_stack; // 栈起始地址unsigned long arg_start, arg_end; // 命令行参数起止unsigned long env_start, env_end; // 环境变量起止// ... 其他字段(如内存映射统计、ASLR标记等)
};
mm_struct中记录了各种段的边界,如代码段、堆、栈等。除此之外,mm_struct内部还指向了一个元素为vm_area_struct的链表,每个vm_area_struct描述一段连续的虚拟地址空间(如ELF的.text
段、堆、栈、共享库等)。
struct vm_area_struct {unsigned long vm_start; // 区域起始地址(虚拟地址)unsigned long vm_end; // 区域结束地址struct mm_struct *vm_mm; // 所属的mm_structpgprot_t vm_page_prot; // 访问权限(读/写/执行)unsigned long vm_flags; // 标志位(如VM_READ、VM_WRITE、VM_EXEC)struct file *vm_file; // 关联的文件(若为文件映射)unsigned long vm_pgoff; // 文件偏移(以页为单位)struct vm_area_struct *vm_next; // 链表中的下一个VMA// ... 其他字段(如反向映射、匿名映射等)
};
在ELF文件的链接阶段,链接器已经将整个文件统一编址。这些地址信息会在加载阶段直接初始化程序的虚拟地址空间,过程如下:
步骤1:程序头表解析
内核通过解析ELF文件的程序头表(Program Header Table)确定需要加载的段(如PT_LOAD
类型),包括代码段(.text
)、数据段(.data
)、只读数据段(.rodata
)等。然后提取每个段的关键信息,比如偏移量、链接阶段确定的虚拟地址、大小和权限等等。因为编址时采用平坦模式,所以偏移量就是虚拟地址。
步骤2:映射虚拟内存
内核为每个 PT_LOAD
段调用 mmap
,将文件内容映射到进程的虚拟地址空间:
void *addr = mmap((void *)p_vaddr, // 请求的虚拟地址(链接时确定)p_memsz, // 内存中段的大小prot_flags, // 权限(如 PROT_READ | PROT_EXEC)MAP_PRIVATE | MAP_FIXED, // 私有映射+固定地址(若未启用ASLR)fd, // ELF文件描述符p_offset // 段在文件中的偏移
);
MAP_FIXED
:强制按 p_vaddr
分配地址,也就是链接时确定的虚拟地址。
权限转换:ELF的 p_flags
(如 PF_X
)转换为 mmap
的 prot_flags
(如 PROT_EXEC
)。
步骤3:填写页表
虚拟地址分配后,实际物理内存的分配是惰性的:CPU访问未映射的虚拟地址时,触发缺页异常(Page Fault)。
内核处理异常:
- 检查VMA权限是否合法。
- 分配物理页,填充文件内容(若为文件映射),或清零(匿名映射)。
- 更新页表:建立虚拟地址到物理地址的映射。
简单来讲,程序的虚拟地址空间的初始化数据从ELF的每个segment来,链接时ELF统一编址后每个segment的地址与大小用来初始化内核空间中的vm_area_struct,再填写mm_struct。之后内核会通过缺页异常产生虚拟地址到物理地址的映射。
3.2静态链接
静态链接(Static Linking)是指在编译阶段将程序依赖的所有外部库(函数、数据等)直接合并到最终的可执行文件中。这样生成的可执行文件是自包含的,运行时不再依赖外部的共享库(如 .dll
、.so
文件)。
静态链接的基本流程:
- 编译阶段:源代码(
.c
、.cpp
)被编译成目标文件(.o
或.obj
)。 - 链接阶段:链接器(如
ld
、link.exe
)将目标文件与静态库(.a
或.lib
)合并,生成独立的可执行文件(如a.out
、.exe
)。 - 运行时:程序直接运行,无需加载额外的动态库。
这里我们举个例子:
首先我们创建两个.c源文件并编写代码,之后将其编译为重定向文件。
//rush.c
#include<stdio.h>void run()
{printf("running...\n");
}
//code.c
#include <stdio.h>
void run();
int main() {printf("Hello, world!\n");run();return 0;
}
gcc -c *.c
我们将两个重定向文件进行反汇编后可以发现,编译器并不知道两个源文件中printf和run函数是什么,所以编译器将两个函数的跳转地址暂时设为0。
objdump -d code.o
objdump -d rush.o
除了将两个重定向文件反汇编,我们还可以通过查看两个文件的符号表,我们也可以看到printf与run都是未定义的:
#读取code.o的符号表
readelf -s code.o
#读取rush.o的符号表
readelf -s rush.o
前文我们讲到,在链接阶段链接器会检查所有未定义符号(如 printf
)是否在其它目标文件或库中定义,并根据重定位表修正代码和数据中的临时地址。所以在链接阶段函数的检查和跳转地址会最终确定。
这里我们将两个.o文件链接形成可执行文件,再次反汇编时我们会发现函数的跳转地址最终确定。
读取该可执行文件的符号表:
最终两个.o的代码段被合并到了一起,并进行了统一的编址。
所以静态链接其实就是将编译之后的所有目标文件连同用到的⼀些静态库在运行时组合,拼装成⼀个独立的可执行文件。其中就包括我们之前提到的地址修正,当所有模块组合在⼀起之后,链接器会根据我 们的.o文件或者静态库中的重定位表找到那些需要被重定位的函数全局变量,从而修正它们的地址。这其实就是静态链接的过程。
3.3 动态链接
在软件开发中,程序通常由主程序代码和各种库函数组成。库函数可以是由操作系统或第三方提供的通用功能模块,如数学计算、文件操作、网络通信等。传统的静态链接方式是在编译时将所有需要的库函数代码直接嵌入到主程序的可执行文件中,导致可执行文件体积较大,且多个程序如果使用相同的库函数,会在内存中存在多份副本,造成资源浪费。
动态链接则打破了这种模式,它允许库函数以独立的动态链接库或共享对象的形式存在。这些库文件在程序运行时被加载到内存中,主程序通过动态链接机制调用其中的函数,实现了代码的共享和复用。
#查看一个可执行文件依赖的动态库
ldd 可执行文件路径
3.3.1 工作时期
在C/C++的程序运行时不会直接跳转到main函数位置开始执行,实际上程序的入口是一个_start函数,它通常是一个C标准库或者链接器提供的一个特殊的函数用来执行一系列初始化操作,这些操作包括:
- 设置栈指针
- 初始化寄存器状态
- 初始化数据段:将程序的数据段(如全局变量和静态变量)从初始化数据段复制到相应的内存位 置,并清零未初始化的数据段
- 动态链接:这是关键的⼀步, _start 函数会调用动态链接器的代码来解析和加载程序所依赖的 动态库(sharedlibraries)。动态链接器会处理所有的符号解析和重定位,确保程序中的函数调用和变量访问能够正确地映射到动态库中的实际地址。
- 调用 __libc_start_main :⼀旦动态链接完成, _start 函数会调用 __libc_start_main (这是glibc提供的⼀个函数)。 __libc_start_main 函数负责执行 ⼀些额外的初始化工作,比如设置信号处理函数、初始化线程库(如果使用了线程)等。
- 调用main 函数:最后,__libc_start_main 函数会调用程序的控制权才正式交给用户编写的代码。
- 处理 main 函数的返回值:main 函数返回时, __libc_start_main 会负责处理这个返回 _exit 函数来终止程序。
动态链接器
在动态链接阶段动态链接器(如ld-linux-x86-64.so.2 )负责在程序运行阶段解析动态库依赖并把动态库加载到内存中。
环境变量与配置文件:
Linux系统通过环境变量(如LD_LIBRARY_PATH)和配置文件(如/etc/ld.so.conf及其子配置文件)来指定动态库的搜索路径这些路径会被动态链接器在加载动态库时搜索。
缓存文件:
为了提高动态库的加载效率,Linux系统会维护⼀个名为/etc/ld.so.cache的缓存文件,该文件包含了系统中所有已知动态库的路径和相关信息,动态链接器在加载动态库时会首先搜索这个缓存文件
3.3.2 动态库的加载与调用
动态库为了随时进行加载,为了支持并映射到任意进程的任意位置,对动态库中的方法统⼀编址, 我们也可以认为动态库是从0地址处开始编址的。
将动态库映射到程序虚拟地址空间:
与可执行程序ELF文件加载时类似,动态链接器会通过访问程序头表(Program Header Table)提取每个段的关键信息,比如偏移量、链接阶段确定的虚拟地址、大小和权限等等。之后内核会在程序虚拟地址空间的共享区为动态库开辟一段内存空间然后用前面提取的动态库的关键信息初始化这片虚拟地址空间。
在将动态库加载到虚拟地址空间后,还需要进行重定位操作。因为动态库在链接阶段确定的虚拟地址可能与实际加载到进程虚拟地址空间中的地址不同,重定位过程就是修改动态库中的相关指令和数据,使其能够正确地引用到实际的内存地址。
之后内核会填写页表建立虚拟与物理内存之间的映射关系。
最后我们需要明白的是,动态库在程序虚拟地址空间中仅占据部分区域,内核会为其分配一个基地址。由于动态库内部采用统一编址(0x00000000至0xFFFFFFFF),访问库内方法或内容只需计算基地址与内部偏移量之和即可。
动态库的调用:
在动态链接阶段动态链接器会在 .data (可执行程序或者库自己)中专门预留⼀片区域用来存放函数的跳转地址,它也被叫做全局偏移表GOT,表中每⼀项都是本运行模块要引用的⼀个全局变量或函数的地址,这些地址本质上就是上述讲到的库起始虚拟地址+ 偏移量,每个进程的每个动态库都有独立的GOT表,所以进程间不能共享GOT表。
重要的是因为.data区域是可读写的,所以可以支持动态进行修改。
此时在代码区调用动态库中某一个方法本质上就是跳转到GOT表查找然后根据表中地址进行跳转,这些地址在动态库加载阶段会被修改为真正的地址(因为只有库加载完成后才能确定起始地址)。
这种方式实现的动态链接就被叫做 PIC 地址无关代码。换句话说,我们的动态库不需要做任何修 改,被加载到任意内存地址都能够正常运行,并且能够被所有进程共享,这也是为什么之前我们给 编译器指定-fPIC参数的原因, PIC=相对编址+GOT。
总结:
- 静态链接的出现,提高了程序的模块化水平。对于⼀个大的项目,不同的人可以独立地测试和开发 自己的模块。
- 通过静态链接,生成最终的可执行文件。我们知道静态链接会将编译产生的所有目标文件,和用到的各种库合并成⼀个独立的可执行文件, 其中我们会去修正模块间函数的跳转地址,也被叫做编译重定位(也叫做静态重定位)。
- 而动态链接实际上将链接的整个过程推迟到了程序加载的时候。比如我们去运行⼀个程序,操作系统会首先将程序的数据代码连同它用到的⼀系列动态库先加载到内存,其中每个动态库的加载地址都是不固定的,但是无论加载到什么地方,都要映射到进程对应的地址空间,然后通过.GOT方式进行调用(运行重定位,也叫做动态地址重定位)。
相关文章:

Linux系统:ELF文件的定义与加载以及动静态链接
本节重点 ELF文件的概念与结构可执行文件,目标文件ELF格式的区别ELF文件的形成过程ELF文件的加载动态链接与静态链接动态库的编址与方法调用 一、ELF文件的概念与结构 1.1 文件概述 ELF(Executable and Linkable Format)即“可执行与可链…...
迷宫与陷阱--bfs+回路+剪枝
1.用bfs板子,同时会出现回路,但不能不用bo数组,要减去一部分没有用的回路 2.什么叫没有用的回路--因为我有无敌了,以前遇到的陷阱就能过了,那这就是有用的回路, 所以我记录(x,y)点…...

【国产化适配】如何选择高效合规的安全数据交换系统?
一、安全数据交换系统的核心价值与国产化需求 在数字化转型浪潮中,企业数据流动的频率与规模呈指数级增长,跨网文件传输已成为日常运营的刚需,所以安全数据交换系统也是企业必备的工具。然而,数据泄露事件频发、行业合规要求趋严…...
基于深度学习的裂缝检测与分割研究方向的 数据集介绍
目录 一、基于深度学习的裂缝检测与分割研究方向 1. 任务定义与挑战 2. 主流方法与技术演进 3. 实际应用优化 二、裂缝检测与分割常用数据集详解 1. SDNET2018 2. CrackTree(CrackTree200) 3. AigleRN 4. CFD(Concrete Crack Detect…...
【Prompt实战】国际翻译小组
本文原创作者:姚瑞南 AI-agent 大模型运营专家/音乐人/野生穿搭model,先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗;多年人工智能行业智能产品运营及大模型落地经验,拥有AI外呼方向国家专利与PMP项目管理证书。&#…...

简化复杂系统的优雅之道:深入解析 Java 外观模式
一、外观模式的本质与核心价值 在软件开发的世界里,我们经常会遇到这样的场景:一个复杂的子系统由多个相互协作的类组成,这些类之间可能存在错综复杂的依赖关系和交互逻辑。当外部客户端需要使用这个子系统时,往往需要了解多个类…...

设计模式杂谈-模板设计模式
在进入正题之前,先引入这样一个场景: 程序员A现在接到这样一个需求:这个需求有10个接口,这些接口都需要接收前端的传参,以及给前端返回业务状态信息。出于数据保密的要求,不管是前端传参还是最终参数返回都…...
LangChain【8】之工具包深度解析:从基础使用到高级实践
文章目录 1. LangChain工具包概述1.1 工具包的基本概念1.2 工具包的主要类型 2. SQL数据库工具包深度解析2.1 基本配置与初始化2.2 数据库连接与验证2.3 工具包初始化与工具获取2.4 创建Agent并执行查询2.5 完整代码 3. 高级使用技巧3.1 自定义工具集成3.2 多工具包组合使用3.3…...

C#入门学习笔记 #6(字段、属性、索引器、常量)
欢迎进入这篇文章,文章内容为学习C#过程中做的笔记,可能有些内容的逻辑衔接不是很连贯,但还是决定分享出来,由衷的希望可以帮助到你。 笔记内容会持续更新~~ 将这四种成语放在一起讲是因为这四种成员都是用来表达数据的。 字段…...

广目软件GM DC Monitor
广目(北京)软件有限公司成立于2024年,技术和研发团队均来自于一家具有近10年监控系统研发的企业。广目的技术团队一共实施了9家政府单位、1家股份制银行、1家芯片制造企业的数据中心监控预警项目。这11家政企单位由2家正部级、1家副部级、6家…...

每日八股文6.6
每日八股-6.6 Mysql1.怎么查看一条sql语句是否走了索引?2.能说说 MySQL 事务都有哪些关键特性吗?3.MySQL 是如何保证事务的原子性的?4.MySQL 是如何保证事务的隔离性的?5.能简单介绍一下 MVCC 吗?或者说,你…...
动静态库的使用(Linux下)
1.库 通俗来说,库就是现有的,可复用的代码,例如:在C/C语言编译时,就需要依赖相关的C/C标准库。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。通常我们可以在windows下看到一些后…...

PostgreSQL17 编译安装+相关问题解决
更新时间:2025.6.6,当前最新稳定版本17.5,演示的是17.5,最新测试版本18beta1 演示系统:debian12 很多时候,只有编译安装才能用上最新的软件版本或指定的版本。这也是编译安装的意义。 一、编译安装 &…...
FFMPEG 提取视频中指定起始时间及结束时间的视频,给出ffmpeg 命令
以下是提取视频中指定起始时间及结束时间的 ffmpeg 命令示例: bash 复制 ffmpeg -i input.mp4 -ss 00:01:30.00 -to 00:05:00.00 -c copy output.mp4 其中,-i input.mp4 是指定要处理的输入视频文件为 “input.mp4”。 -ss 00:01:30.00 表示指定视频的起始时间为 1 分 30 …...

React 第五十六节 Router 中useSubmit的使用详解及注意事项
前言 useSubmit 是 React Router v6.4 引入的强大钩子,用于以编程方式提交表单数据。 它提供了对表单提交过程的精细控制,特别适合需要自定义提交行为或非标准表单场景的应用。 一、useSubmit 核心用途 编程式表单提交:不依赖 <form>…...

华为云学堂-云原生开发者认证课程列表
华为云学堂-云原生认证 云原生开发者认证的前5个课程...
Vue.js 组件:深入理解与实践
Vue.js 组件:深入理解与实践 引言 随着前端技术的不断发展,Vue.js 作为一种流行的前端框架,因其简洁、易学、高效的特点受到越来越多开发者的青睐。在Vue.js中,组件是构建用户界面的基石。本文将深入探讨Vue.js组件的概念、特性、创建方式以及在实际开发中的应用,帮助读…...
什么是强化学习:设置奖励函数最为loss, 监督学习:标签准确率作为loss
什么是强化学习:设置奖励函数最为loss, 监督学习:标签准确率作为loss 什么是强化学习:在复杂环境中自主探索,适用于序列决策 最大优势: 通过试错探索发现最优策略,适应环境动态变化,擅长解决需要长期规划和序列决策的问题。典型案例: 游戏AI(如AlphaGo/AlphaZero):…...

理解网络协议
1.查看网络配置 : ipconfig 2. ip地址 : ipv4(4字节, 32bit), ipv6, 用来标识主机的网络地址 3.端口号(0~65535) : 用来标识主机上的某个进程, 1 ~ 1024 知名端口号, 如果是服务端的话需要提供一个特定的端口号, 客户端的话是随机分配一个端口号 4.协议 : 简单来说就是接收数据…...
placeholder不显示and模板字符串无效
一、placeholder"请输入"不显示请输入? input框里写了placeholder为什么不显示呢? 检查代码,input是否有初始值 在 Vue.js 中,v-model 是双向绑定的语法糖,它会动态更新输入框的 value。如果绑定的数据有初…...
在MyBatis中设计SQL返回布尔值(Boolean)有几种常见方法
方案一:使用COUNT查询存在性(推荐) <select id"checkUserExists" resultType"_boolean">SELECT COUNT(*) > 0 FROM users WHERE username #{username} </select> 说明: MySQL中COU…...

全球知名具身智能/AI机器人实验室介绍之AI FACTORY基于慕尼黑工业大学
全球知名具身智能/AI机器人实验室介绍之AI FACTORY基于慕尼黑工业大学 TUM AI FACTORY,即KI.FABRIK,是德国慕尼黑工业大学(TUM)在巴伐利亚州推出的一个旗舰项目,旨在打造未来工厂,将传统工厂转变为由人工智…...

DASCTF
[DASCTF X 0psu3十一月挑战赛|越艰巨越狂热]EzPenetration Tip:数据库里的邮箱key已更改为管理员密码,拿到后可直接登录 打开靶机,用Wappalyzer分析网站,可以看到管理系统是Wordpress,因此可以尝试用WPSSCAN扫描公开…...
钉钉 - 机器人消息推送(签名版)
前言 在日常生活中,我们可能会遇到某些异常发生后需要紧急通知到群里,让相关人员看到紧急处理的事件触发机制。 消息群我采用的是钉钉推送,本文介绍了如何用php 推送钉钉机器人消息。 源码封装 <?php /*** 钉钉通知 - 签名版*/ class …...
Redux 实践与中间件应用
Redux 异步处理的挑战 Redux 核心设计是同步的、单向数据流,但现代应用中异步操作无处不在。Redux 中间件填补了这一缺口,专门解决异步流程管理、副作用隔离等复杂场景。 中间件架构原理 中间件位于 action 被发起之后、到达 reducer 之前,…...

ModBus总线协议
一、知识点 1. 什么是Modbus协议? Modbus 是一种工业通信协议,最早由 Modicon 公司在1979年提出,目的是用于 PLC(可编程逻辑控制器)之间的数据通信。它是主从式通信,即一个主机(主设备…...

【计算机网络】非阻塞IO——poll实现多路转接
🔥个人主页🔥:孤寂大仙V 🌈收录专栏🌈:计算机网络 🌹往期回顾🌹:【计算机网络】非阻塞IO——select实现多路转接 🔖流水不争,争的是滔滔不息 一、…...
在.NET Core控制器中获取AJAX传递的Body参数
.Net Core是支持前后端不分离式的开发的,如果在原始系统中采用不分离式开发,后面需要在原系统中增加功能,并且新的服务采用其他语言开发,且系统原来功能保持原样,这样前端系统可以单独调用新开发的接口。 但是&#x…...
snprintf函数用法及注意事项详解
当 format 后没有可变参数(即 ... 为空)时,va_start 的行为和后续操作如下: 1. va_start 的行为 va_start 的核心任务是根据最后一个固定参数(format)的地址,计算可变参数列表的起始位置。即使…...
vue-20(Vuex 状态管理的最佳实践)
Vuex 状态管理的最佳实践 Vuex 是管理大型 Vue.js 应用状态的一个强大工具,但其有效性取决于其组织和维护的质量。管理不善的 Vuex 存储可能会变得难以控制、难以调试,并成为性能瓶颈。本课程深入探讨构建 Vuex 存储的最佳实践,重点关注可维…...