ELF与库加载

对上一篇博客的补充:
结论1:当编译时,链接器发现同一个库同时存在动态库(.so)和静态库(.a)版本时,默认会优先链接动态库。

结论2:如果想强制使用静态库进行链接,需要在编译命令中加上-static选项。

结论3:使用-static选项的前提是,对应库必须确实提供了静态库版本。如果某个库只有动态库,那么即使加了-static,对于该库,链接器也只能进行动态链接。

结论4:如果某个库只提供了静态库(没有对应的动态库),那么即使你采用默认的动态链接方式,对于这个特定的库,链接器也只能进行静态链接。但程序仍然可以对其他提供了动态库的库进行动态链接。

结论5:-static选项是一个全局性要求。它强制要求程序所依赖的所有库都必须有对应的静态库版本,并且全部以静态链接的方式打包进最终的可执行程序中。

图1:链接器选择库的流程示意图

结论6:以fopen函数为例,其返回值FILE*指向的结构体对象,其内存空间实际上是由库函数内部调用malloc等函数为用户申请的。也就是说,申请内存这个动作的源代码实现在库的内部,但最终申请内存的“责任人”和消耗系统资源的仍然是调用该库函数的用户进程。

这里写目录标题

  • 真正调用别人的库
  • 编译过程
    • 预处理阶段(Preprocessing)
    • 编译阶段(Compilation)
    • 汇编阶段(Assembly)
  • 可执行程序与ELF格式
    • ELF格式简介
      • ELF格式细节
        • 程序头表中的“段”与进程地址空间
        • CPU 如何找到第一条指令?
      • 查看 ELF 文件结构
        • 1. 查看 ELF 头(ELF Header)
        • 2. 查看节头表(Section Headers)
        • 3. 查看程序头表(Program Headers)
    • 节vs段
  • 可执行程序的加载与虚拟地址空间
    • 加载顺序:先有数据结构还是先加载文件?
    • 编译时地址:程序在磁盘上有地址吗?
    • 深入理解:平坦模式与地址概念辨析
  • 可执行程序的加载与地址空间映射
  • 动态库的加载机制
    • 多进程共享动态库

真正调用别人的库

编译过程

预处理阶段(Preprocessing)

  • 文件后缀:.i
  • 阶段任务:处理源代码中以#开头的预处理指令。例如,将#include <ncurses.h>包含的头文件内容完整展开到代码中、替换#define定义的宏、删除代码中的注释等。

编译阶段(Compilation)

  • 文件后缀:.s
  • 阶段任务:将预处理后的.i文件进行词法分析、语法分析和语义分析,最终翻译成汇编语言代码(人类勉强能看懂的低级语言)。

汇编阶段(Assembly)

  • 文件后缀:.o(在 Windows 系统下通常是.obj)
  • 阶段任务:将汇编代码翻译成机器能直接识别的二进制机器码。这个阶段的产物称为目标文件(全称:可重定位目标文件)。此时生成的文件还不能直接运行,因为其中引用的外部函数(例如ncurses库里的函数)地址尚未最终确定。

可执行程序与ELF格式

可执行程序是一个二进制文件,但它并非随意堆砌的二进制数据,而是具有特定的内部结构和格式。

这个格式,我们称之为 ELF 格式。

ELF格式简介

ELF(Executable and Linkable Format),即可执行与可链接格式,是 Unix/Linux 系统下可执行文件、目标文件、共享库和核心转储(core dumps)的标准文件格式。

ELF 文件主要分为四种类型:

  1. 可重定位文件(Relocatable File):即.o目标文件。包含代码和数据,适合于与其他目标文件链接以创建可执行文件或共享库。
  2. 可执行文件(Executable File):即可直接运行的程序。
  3. 共享目标文件(Shared Object File):即.so动态链接库文件。
  4. 核心转储(Core Dumps):存放进程意外终止时的执行上下文(内存映像、寄存器状态等),主要用于调试和信号分析。

ELF格式细节

一个 ELF 文件由以下四个核心部分组成:

  1. ELF 头(ELF Header)
    位于文件起始位置,描述了文件的主要特性(如文件类型、机器架构、入口点地址等)。它的主要作用是定位文件的其他部分,并管理整个 ELF 文件的属性信息。

  2. 程序头表(Program Header Table)
    列举了所有有效的**段(Segments)**及其属性。表中记录了每个段在文件中的起始位置(偏移量)、长度等信息。由于这些段在二进制文件中是紧密排列的,需要依赖程序头表的描述信息才能将它们正确分割和识别。

  3. 节头表(Section Header Table)
    包含了对所有**节(Sections)**的描述信息。节是 ELF 文件的基本组成单位。

  4. 节(Section)
    ELF 文件的基本组成单元,用于存储特定类型的数据。文件的各种信息(如可执行代码、全局变量、字符串常量等)都分类存储在不同的节中。一个节内的数据通常具有相同的类型。

    • 代码节(.text):存储程序的机器指令,是主要的可执行部分。
    • 数据节(.data):存储已初始化的全局变量和静态变量。

    注: ELF的节是给编译链接器使用的,用来划分代码、常量、符号等原始数据;段是给操作系统加载程序使用的,链接过程会把权限属性相同的多个节合并成一个段,内核以段为单位映射到内存运行。
    汇编生成含节的 .o 文件;链接器合并目标文件,将节打包成段、生成程序头表;内核加载ELF,读取程序头表,按段映射到虚拟内存。

图2:ELF 文件结构示意图

程序头表中的“段”与进程地址空间

程序头表描述的“段”(Segment)与进程的虚拟地址空间密切相关。当执行一个可执行程序时,操作系统会为其创建进程控制块(PCB),并建立虚拟地址空间。那么,这个地址空间应该如何划分?具体有多少个区域?每个区域又对应什么内容?这些问题的答案都与 ELF 文件中的程序头表信息直接相关。

图3:进程虚拟地址空间与 ELF 段映射示意图

CPU 如何找到第一条指令?

ELF 文件本质上是一种存储在磁盘上的文件格式。结合对磁盘存储的理解,我们可以将 ELF 文件视为一个“数组”,只不过这个“数组”的每个“元素”(即磁盘块)大小通常为 4KB。

那么,CPU 是如何知道从哪里开始执行第一条指令的呢?这需要通过特定的工具来查看 ELF 文件头中的关键信息。

查看 ELF 文件结构

1. 查看 ELF 头(ELF Header)

使用readelf -h命令可以查看目标文件的 ELF 头信息。

readelf-hhello.o

其中,Entry point address(入口点地址)是最重要的字段之一。它指明了未来可执行程序加载到内存后,CPU 开始执行的第一条指令的地址。

2. 查看节头表(Section Headers)

使用readelf -S命令可以查看目标文件包含的所有节(Section)的详细信息。

readelf-Shello.o

  • Offset(偏移量):表示该节相对于文件起始位置的字节偏移量。
  • Size(大小):表示该节所占的字节数。
  • Flags(标志位):表示该节的访问权限(如可读R、可写W、可执行E)。

节在文件中的布局规律:通常情况下,当前节的起始偏移量(Offset)等于上一个节的起始偏移量加上其大小(Size),再加上可能存在的对齐填充(Alignment Padding)。

符号与引用:.symtab节(符号表)存储了程序中定义的函数和变量名(符号)及其地址信息。当不同的变量或函数引用同一个地址时,相关的信息就记录在这个节中。

3. 查看程序头表(Program Headers)

使用readelf -l命令可以查看目标文件的程序头表,它描述了文件中的各个段(Segment)。

readelf-lhello.o


在程序头表的上下文中,Segment 通常被翻译为“段”,它描述了文件内容在加载到内存时应如何被组织成具有特定权限(如可读、可写、可执行)的内存区域。

节vs段

在ELF文件中,并不直接存在“段”(Segment)这一物理存储单元,而是存在一个个的“节”(Section)。这些节的大小各不相同,且可以拥有相同的访问权限。

“节”(Section)确实是存储在磁盘上的,更准确地说,它是可执行文件(如Windows的.exe文件或Linux的ELF文件)在磁盘上的一种内部组织结构。

ELF文件本身存储在磁盘上。当操作系统(OS)需要加载可执行程序时,会以4KB(页大小)为单位将文件内容读取到内存中。如果ELF文件中包含大量独立的节,直接逐个加载会占用大量内存空间。为了高效利用宝贵的内存资源,加载器(Loader)会在加载过程中,将多个具有相同访问权限(如可读、可写、可执行)的节合并成一个更大的内存区域,这个合并后的区域就称为“段”(Segment)。图3中展示的代码段、数据段等,正是这些合并后的内存段。

因此,在加载并运行可执行程序时,操作系统首先查看的是程序头表(Program Headers Table),它描述了这些最终将被加载到内存中的“段”的信息。

可执行程序的加载与虚拟地址空间

在理解了 ELF 文件的结构之后,我们继续探讨可执行程序是如何被加载到内存中并运行的。这涉及到进程地址空间的创建与映射。

加载顺序:先有数据结构还是先加载文件?

一个常见的疑问是:操作系统在运行一个程序时,是先创建内核进程相关的数据结构(如 PCB、页表、地址空间),还是先加载 ELF 二进制文件?

答案是:先创建内核进程相关的数据结构,再加载 ELF 的二进制文件。

操作系统首先会为即将运行的程序创建一个“空壳”进程,即初始化进程控制块(PCB)、建立空的页表和虚拟地址空间等核心数据结构。这个过程确定了进程在内核中的身份和资源框架。然后,加载器(Loader)才会根据 ELF 文件的程序头表(Program Header Table),将文件中的各个段(Segment)映射到这个已经创建好的虚拟地址空间中,并填充页表,最终使程序代码和数据变得可访问、可执行。

编译时地址:程序在磁盘上有地址吗?

第二个关键问题是:程序在编译链接完成之后,尚未被加载到内存时,它自身有没有地址?如果有,是什么地址?

答案是:“都有地址”。

编译器在编译可执行程序时,会采用一种称为平坦模式(Flat Mode)的编址方式。在这种模式下,编译器会对程序中的每一条指令、每一个数据(即“每一行”代码或数据单元)都分配一个逻辑地址。原则上,这个地址空间从 0 开始编号。

  • 在 32 位系统下,这个地址范围理论上是从0x00000000到0xFFFFFFFF(即从全 0 到全 1)。
  • 这个在编译时就确定好的、连续的地址空间,被称为虚拟地址(Virtual Address)。

重要理解:这些虚拟地址在编译和链接阶段就已经存在于磁盘上的 ELF 文件中了(例如,存储在.text节和.data节里的指令和数据都带有虚拟地址)。程序此时还在磁盘上,并未加载到物理内存。只有当程序运行时,操作系统才会将其从磁盘加载到物理内存,并通过页表机制,将这些预先编好的虚拟地址映射到实际的物理内存地址上。

因此,虚拟地址空间可以理解为一套“标准”或“约定”:

  1. 操作系统(OS)遵守它:OS 负责在加载程序时,建立并维护虚拟地址到物理地址的映射(页表)。
  2. 编译器也遵守它:编译器按照这套地址规范来生成目标代码,确保程序中的指令和数据引用都使用正确的虚拟地址。

深入理解:平坦模式与地址概念辨析

上文提到的“平坦模式”可以简单理解为从 0 开始加上一个偏移量(0 + 偏移量)的连续线性地址空间。需要明确的是,“平坦模式”本身并不是地址,而是一种内存寻址的规则或模型。正是由于采用了这种规则,逻辑地址和虚拟地址在数值上才得以完全等同。

我们可以从以下三个层面来理解它们之间的关系:

  1. 平坦模式(规则)
    它的核心思想是将整个内存空间视为一条从 0 到最大值(例如 32 位系统下的 4GB)的、连续且不分段的“直线”。在这条直线上,没有“几号楼几零几(段:偏移量)”的复杂层级概念,只有“第几号房间(线性地址)”这一个维度。这种模型简化了地址的表示和计算。

  2. 磁盘上:逻辑地址(程序发出的原始地址)
    在传统的 x86 架构中,逻辑地址由“段基址 + 偏移量”两部分组成。然而,在平坦模式下,操作系统为了简化内存管理,将所有段的“段基址”都强制设置为 0。此时,逻辑地址的计算公式就简化为:0 + 偏移量 = 偏移量。因此,逻辑地址的数值就退化为了单纯的偏移量。

  3. 操作系统:虚拟地址(操作系统呈现的线性地址)
    由于逻辑地址计算出的结果就是那个单纯的“偏移量”,而这个偏移量恰好对应平坦模式下那条“直线”上的某个位置。因此,逻辑地址的偏移量就直接等于虚拟地址(线性地址)。可以说,在平坦模式下,逻辑地址经过段机制的“零基址”处理后,其表现形式与虚拟地址完全一致。

为了更清晰地辨析这些概念,下表对比了逻辑地址与虚拟地址的关键差异:

维度逻辑地址 (Logical Address)虚拟地址 (Virtual Address)
核心组成段选择符 (Segment Selector) + 段内偏移量 (Offset)单一的、连续的线性地址(没有段结构)
处理阶段处于段式内存管理阶段,是 CPU 硬件分段机制的产物处于页式内存管理阶段,是分段地址转换后的结果
谁来生成由程序本身(编译器生成的代码或 CPU 指令)直接生成由硬件的段管理单元 (Segment Unit) 将逻辑地址转换而来
直观理解程序员或编译器视角的“相对位置”,需要结合段基址才能最终定位操作系统为每个进程绘制的“平坦大饼”,是一个统一的、从 0 开始的连续视图

简单来说,在 x86 架构的保护模式下,程序代码中直接出现的是逻辑地址(例如CS:IP)。CPU 的段管理单元会将其转换为线性地址(即虚拟地址),随后页管理单元再将这个虚拟地址转换为最终的物理地址。现代操作系统普遍采用“平坦模式”,即通过将所有段的基址设为 0,使得逻辑地址中的偏移量部分直接等同于虚拟地址,从而极大地简化了内存管理。

可执行程序的加载与地址空间映射

当可执行程序被加载到物理内存时,其指令和数据既需要虚拟地址,也需要对应的物理地址来存储。然而,在程序尚未加载之前,物理地址空间尚未分配,但虚拟地址空间已经存在。正如前文所述,进程的task_struct结构体中的mm_struct成员负责管理虚拟地址空间,其初始化数据来源于磁盘上的可执行文件。加载器(Loader)正是根据 ELF 文件的程序头表信息,将文件中的各个段(Segment)映射到这个预先建立的虚拟地址空间中,并建立虚拟地址到物理地址的页表映射,最终完成程序的加载过程。

当mm_struct结构体初始化完毕,加载器(Loader)便开始工作。它根据 ELF 文件的程序头表,将文件的各个段(Segment)映射到进程的虚拟地址空间中。在这个过程中,操作系统会为这些虚拟地址区域分配物理内存页,并动态地建立虚拟地址到物理地址的页表映射。映射的建立是随着加载过程逐步完成的,并非在所有物理地址分配完毕后才一次性填充。

当所有必要的段都加载完毕,页表映射也建立完成后,CPU 便可以从可执行程序的 ELF 头(ELF Header)中读取入口点地址(Entry Point Address)。操作系统会将这个入口点的虚拟地址加载到指令指针寄存器(EIP/RIP)中。随后,CPU 便从这个地址开始,通过程序计数器(PC)指针依次取指并执行程序指令。

在程序内部的时候,要调用函数地址,这个地址是什么地址?虚拟地址,cpu进来的地址,都是虚拟地址。cpu内部还有个CR3,他会指向页表,还有一个MMU当CPU拿到了虚拟地址,会把虚拟地址交给MMU,MMU会通过CR3去访问页表,至此,从CPU中出来的地址,就全是物理地址了。从虚拟地址转化到物理地址,全是在CPU中完成的。
总结一下:虚拟地址空间,不仅仅让OS参与,编译器也要参与这个过程。

总结一下整个流程:
程序加载的本质,就是把 ELF 文件的各个段,通过 mm_struct 规划到进程的虚拟地址空间中,并在 CPU 真正访问时,由操作系统通过缺页异常分配物理内存,最终利用页表建立起“虚拟地址 -> 物理地址”的映射关系。这样,程序以为自己独占了一整块连续的内存,而实际上它的代码和数据可能散落在物理内存的各个角落。

动态库的加载机制

动态库的加载与进程的虚拟地址空间管理密切相关。每个进程的进程控制块(PCB)中都有一个mm指针,它指向一个mm_struct结构体。这个结构体负责管理进程的虚拟地址空间,其中包含了描述地址空间布局的数据以及指向各个内存区域的指针。

动态库在加载时,会被映射到进程虚拟地址空间的共享区。如下图所示,动态库的代码和数据被映射到多个进程共享的虚拟地址区域:

多进程共享动态库

对于多个进程同时使用同一个动态库的情况,操作系统采用了高效的共享机制:在物理内存中,同一个动态库只需要存在一份副本。

当多个进程加载同一个动态库时,操作系统会将这个动态库的代码段(.text)映射到各个进程的虚拟地址空间共享区。由于代码段通常是只读的,多个进程可以安全地共享同一份物理内存中的代码。对于数据段,如果包含可写数据,操作系统会使用写时复制(Copy-On-Write)技术,确保进程间的数据隔离。

这种设计带来了显著的优势:

  1. 节省内存:多个进程共享同一份物理内存中的库代码,大幅减少内存占用。
  2. 提高加载速度:后续进程加载同一动态库时,可以直接映射已加载到内存的库,无需从磁盘重复读取。
  3. 便于更新:更新动态库时,只需替换磁盘上的库文件,新启动的进程会自动使用新版本。

下图展示了多个进程共享同一动态库的示意图:

相关新闻

C语言:自定义类型之联合和枚举

C语言:自定义类型之联合和枚举

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:43:07 阅读更多 →
TIA博途V16 HMI仿真失败排查:组件与显卡驱动修复指南

TIA博途V16 HMI仿真失败排查:组件与显卡驱动修复指南

简介&#xff1a;针对西门子TIA博途V16用户在项目仿真环节频发的无法启动、仿真失败问题&#xff0c;这份DOCX文档整理了完整的故障现象、原因分析与处理方法&#xff0c;适合工业自动化工程师、PLC调试与维护人员作为现场排查手册。内容按面板类型分类&#xff0c;覆盖SMART L…

2026/10/20 1:43:07 阅读更多 →
别被SWE-bench榜单骗了:从ARC-AGI-2到Java后端工程的真实能力映射|TaoToken统一Key实测

别被SWE-bench榜单骗了:从ARC-AGI-2到Java后端工程的真实能力映射|TaoToken统一Key实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:43:07 阅读更多 →

最新新闻

Java AI Agent生态全景 —— Spring AI vs LangGraph4j vs LangChain4j

Java AI Agent生态全景 —— Spring AI vs LangGraph4j vs LangChain4j

引子&#xff1a;一个后端团队的框架选型困局 你所在的Java后端团队接到一个需求&#xff1a;给现有的Spring Boot微服务集群加一个“智能运维助手”——它能查询服务健康状态、分析异常日志、执行简单的运维操作&#xff08;重启服务、扩容、回滚部署&#xff09;&#xff0c…

2026/10/20 2:21:27 阅读更多 →
DevEco Studio Debug调试(一)

DevEco Studio Debug调试(一)

一、设置断点调试过程中可以添加断点&#xff1a;断点设置很简单&#xff1a;在代码行号左侧点击即可添加断点设置断点后&#xff0c;调试能够在正确的断点处中断&#xff0c;并高亮显示该行二、启动调试步骤一&#xff1a;选择调试设备在设备选择框中&#xff0c;选择调试的设…

2026/10/20 2:21:27 阅读更多 →
交叉熵损失函数到底在惩罚什么:3个NumPy实验实战讲透,ML数学基础第4期

交叉熵损失函数到底在惩罚什么:3个NumPy实验实战讲透,ML数学基础第4期

上一期我们手算了 softmax&#xff1a;把一堆分数变成概率&#xff0c;加起来等于 1。概率有了&#xff0c;新的问题来了&#xff1a;训练的时候&#xff0c;怎么判断模型"猜得好不好"&#xff1f;光看答对没答对太粗糙。90% 把握答对&#xff0c;和 51% 把握蒙对&am…

2026/10/20 2:21:27 阅读更多 →
「记忆越少反而越聪明」:Hy-Memory 的反直觉设计为什么被全网热议

「记忆越少反而越聪明」:Hy-Memory 的反直觉设计为什么被全网热议

「记忆越少反而越聪明」&#xff1a;Hy-Memory 的反直觉设计为什么被全网热议 【免费下载链接】Hy-Memory 项目地址: https://gitcode.com/gh_mirrors/hy/Hy-Memory 2026 年 10 月 16 日&#xff0c;腾讯混元将 Hy Memory 2.0 整体开源&#xff1a;hy-memory SDK&#…

2026/10/20 2:21:27 阅读更多 →
【C++/Qt 进阶】设计模式系列(5):适配器模式——给“不兼容的接口“贴一层翻译膜

【C++/Qt 进阶】设计模式系列(5):适配器模式——给“不兼容的接口“贴一层翻译膜

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 2:21:27 阅读更多 →
【沃思智能景观照明节能控制:点亮城市夜色,守护每一度电】

【沃思智能景观照明节能控制:点亮城市夜色,守护每一度电】

亮化工程是城市夜景的点睛之笔&#xff0c;从地标建筑到滨水步道&#xff0c;从主题公园到商业街区&#xff0c;景观照明用光与影塑造着城市的夜间表情。然而&#xff0c;璀璨夺目的背后&#xff0c;往往伴随着高昂的电费账单、繁重的运维压力以及日益受关注的光污染问题。如何…

2026/10/20 2:20:27 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →