C++ 编译过程全解析:从源码到可执行文件的蜕变之旅

引言

C++ 作为一种广泛应用于系统开发、游戏编程、嵌入式系统等领域的高级编程语言,其代码需要经过编译才能转换为计算机可执行的机器语言。编译过程涵盖多个复杂阶段,每个阶段对最终生成的可执行文件的性能、稳定性及兼容性都有着深远影响。深入理解 C++ 编译过程,对于开发者优化代码、排查错误、提升程序整体质量至关重要。本文将全面剖析 C++ 编译过程,帮助开发者精准把握其精髓,提升编程实践水平。

一、C++ 编译流程详述

在这里插入图片描述

1.1 预处理阶段

预处理是编译的起始环节,由预处理器负责执行。此阶段主要处理以 # 开头的预处理指令,这些指令犹如给编译器下达的特殊命令,引导编译器对源代码进行初步调整。

  • 头文件包含:当遇到 #include 指令时,预处理器会将指定头文件的全部内容插入到源文件中该指令所在位置。例如,源文件包含 #include <iostream>,预处理器就会把 <iostream> 头文件里关于输入输出流的函数声明、类定义等内容完整地拷贝过来。这一操作使得源文件能够使用头文件中声明的各类函数、变量及类,极大地拓展了代码的复用性与功能性。

  • 宏展开#define 指令用于定义宏,预处理器会把代码中出现的宏标识符替换为对应的宏定义内容。像 #define PI 3.14159,在预处理后,代码里所有的 PI 都会被替换成 3.14159,实现常量值的统一设定,方便代码维护与修改。

  • 条件编译:通过 #ifdef#ifndef#else#endif 等指令,能够依据特定条件决定代码片段是否参与编译。例如,#ifdef DEBUG#endif 之间的代码仅在定义了 DEBUG 宏时才会被编译,这对于在调试阶段输出额外信息、执行特定测试代码极为便利。

  • 注释过滤:预处理器会移除源文件中的所有注释内容,无论是以 // 开头的单行注释,还是位于 /* */ 之间的多行注释,均被剔除。这一操作简化了后续编译步骤的处理,使编译器专注于有效代码分析。

完成上述处理后,预处理器会生成一个通常以 .i.ii 为扩展名的预处理文件,该文件保留了处理后的源代码全貌,为下一阶段编译提供基础输入。

1.2 编译阶段

编译阶段是将预处理后的文件转换为汇编语言的关键过程,编译器在此承担核心转换任务,涵盖多个精细步骤:

  • 词法分析:编译器首先对预处理文件进行词法扫描,依据 C++ 语言的词法规则,将源文件的字符流拆分成一个个基本的单词单元,即记号(Token)。这些记号涵盖关键字(如 ifwhileclass 等)、标识符(变量名、函数名等自定义名称)、常量(数值常量、字符常量、字符串常量)、运算符(+-*/ 等)及界符(;:{} 等)。

  • 语法分析:基于词法分析得到的记号序列,编译器运用语法规则进行分析,构建出对应的语法树。语法树以树形结构呈现代码的语法结构,节点表示语法成分,如表达式、语句、函数定义、类声明等。

  • 语义分析:进一步深入探究代码含义,编译器在此阶段核查变量和函数的使用是否合规、类型是否匹配等语义问题。

  • 代码优化:编译器运用多种优化技术对代码进行转换与精简,旨在提升程序运行效率、减少资源消耗。常见优化技术包括常量折叠、内联函数、公共子表达式消除等。

经过编译阶段的精细处理,编译器最终生成以 .s 为扩展名的汇编代码文件,该文件以汇编语言形式展现源文件逻辑,为进一步转换为机器码做准备。

1.3 汇编阶段

汇编阶段,汇编器担纲主力,将编译器生成的汇编代码转换为机器可直接识别执行的机器码,这一过程是从文本指令迈向二进制指令的关键跨越。

汇编器逐行解析汇编代码,依据特定处理器架构的指令集规范,将每条汇编指令转换为对应的二进制机器码序列。例如,对于常见的 x86 架构,汇编指令 mov eax, 5(将常量 5 传送到寄存器 eax)会被转换为相应的二进制机器码 B8 05 00 00 00(不同指令集机器码格式各异)。

完成转换后,汇编器生成以 .o.obj 为扩展名的目标文件。这些目标文件是二进制格式,包含机器码指令、数据以及符号表、重定位信息等元数据。

1.4 链接阶段

链接阶段作为编译流程的收官环节,链接器负责整合多个目标文件及所需库文件,生成最终能在操作系统上运行的可执行文件。

  • 符号解析与重定位:链接器首先扫描所有输入的目标文件及库文件,构建全局符号表,将各个文件中的符号定义与引用进行匹配关联。对于目标文件中引用但未定义的符号(如调用外部函数或访问其他文件定义的全局变量),链接器在其他文件中查找定义,确定其真实内存地址,并更新目标文件中的引用信息,使程序运行时能准确跳转至相应地址执行。

  • 段合并与调整:不同目标文件包含代码段(存放可执行指令)、数据段(存储已初始化全局变量、静态变量)、.bss 段(预留未初始化全局变量、静态变量空间)等多个段,链接器将同名段合并,统一编排内存布局,计算各段在最终可执行文件中的偏移地址,确保程序加载运行时内存分配合理有序。

链接过程依据库文件使用方式分为静态链接与动态链接:

  • 静态链接:链接时,将所需库文件中的代码与数据完整拷贝至可执行文件,生成独立、自包含的可执行程序。优点是运行时无需额外依赖库文件,执行效率高,启动速度快;缺点是导致可执行文件体积庞大,若多个程序使用相同库,会造成内存中库代码冗余存储,资源浪费,且库更新时需重新编译所有关联程序。

  • 动态链接:编译时仅在可执行文件中记录所需动态库的名称、符号等信息,程序运行时,操作系统加载器依据这些信息动态加载共享的动态链接库到内存,并完成符号解析与重定位。优势在于多个程序可共享同一动态库,节省内存;动态库更新时,无需重新编译程序,便于维护升级;缺点是程序启动时需额外时间加载动态库,运行过程中若动态库缺失或版本不兼容易引发错误,且存在一定安全风险,如动态库路径被篡改可能导致恶意代码注入。
    在这里插入图片描述

二、C++ 编译优化策略

2.1 编译时优化

编译时优化由编译器在编译阶段自动执行,旨在减少运行时计算开销、提升程序执行效率,诸多实用技术广泛应用于现代编译器中。

  • 常量折叠:编译器对编译期能确定结果的常量表达式提前求值,将表达式替换为常量值。例如,const int a = 5 + 3;,编译器直接将 a 赋值为 8,后续代码使用 a 处直接用 8 替代,避免运行时重复加法运算。

  • 内联函数:针对短小、频繁调用的函数,编译器将函数体嵌入调用点,减少函数调用开销。像 inline int add(int x, int y) { return x + y; },在调用 add 函数处,编译器直接替换为 x + y 计算代码,省却函数调用的参数传递、栈帧创建销毁等额外开销,加速程序执行。

  • 模板优化:模板代码在编译时依据具体类型实例化生成特定代码,编译器借此施展更多优化手段。以通用排序函数模板为例,template<typename T> void sort(T arr[], int size);,当用于 int 型数组排序时,编译器生成适配 int 类型的排序代码,针对 int 数据特性(如固定大小、内存对齐等)优化,比通用代码更高效。

2.2 循环优化

循环作为程序频繁出现的结构,其优化对性能提升意义重大,编译器与开发者可从多维度实施优化策略。

  • 循环展开:通过将循环体重复展开,减少循环控制语句执行次数,提升指令级并行度。例如,for (int i = 0; i < 100; i++) { do_something(i); },若展开为 for (int i = 0; i < 100; i += 4) { do_something(i); do_something(i + 1); do_something(i + 2); do_something(i + 3); },循环控制指令(如比较、递增操作)从 100 次降为 25 次,每次迭代能执行更多有效操作。

  • 循环不变代码外提:把循环中不依赖循环变量、每次迭代结果相同的代码移至循环外,避免重复计算。如 for (int i = 0; i < 100; i++) { int a = 5 * 2; do_something(a, i); },可优化为 int a = 5 * 2; for (int i = 0; i < 100; i++) { do_something(a, i); },提前计算 a 值,降低计算成本。

2.3 内存访问优化

内存访问速度常是程序性能瓶颈,优化内存访问能充分挖掘硬件性能,提升程序整体效率。

  • 数据局部性优化:分空间与时间局部性,前者指程序倾向访问临近内存位置数据,后者指近期访问数据短期内可能再次访问。利用此特性,合理组织数据结构与算法可提升缓存命中率。如多维数组遍历,按行优先(C、C++ 默认)比列优先更契合缓存读取顺序,因连续内存存放同行元素。

  • 内存管理优化:高效的内存分配与回收是关键。避免频繁小块内存动态分配(如在循环内),以减少内存碎片化与分配开销,必要时提前一次性分配大块内存,按需分割使用;对不再使用内存及时释放,防止内存泄漏累积拖慢程序。

2.4 并行化与向量化

随着硬件多核、SIMD 技术发展,利用并行与向量化提升性能成重要方向,适配编译器与编程库为开发者赋能。

  • 并行化:借助多核心处理器并行执行特性,将任务拆分至多个线程或进程同步运行,加速计算。如使用 OpenMP 库,在循环前添加 #pragma omp parallel for 指令,编译器自动将循环迭代分配至多核心。

  • 向量化:编译器将数据按特定宽度(如 128 位、256 位)拆分为向量,运用 SIMD 指令集并行处理,单指令操作多数据元素,提升计算效率。现代处理器 SSE、AVX 指令集广泛支持向量化,对数组运算、图像处理等数据密集型任务效果卓越。

三、跨平台编译挑战与应对

3.1 跨平台开发问题剖析

跨平台开发面临诸多棘手难题,根源在于不同平台在硬件架构、系统特性及编译器支持等多方面存在显著差异。

  • 硬件架构差异:不同平台处理器指令集架构大相径庭,如常见的 x86x86_64ARMMIPS 等架构,各自指令集功能、格式与编码规则截然不同。ARM 架构常用于移动设备与嵌入式系统,注重能耗与性能平衡,指令集精简高效;x86_64 广泛应用于桌面与服务器领域,指令集丰富强大,能处理复杂运算任务。

  • 系统特性差异

    • 内存管理:不同操作系统内存管理机制差异明显。Windows 系统内存分配粒度、内存布局与 Linux 系统存在差别,Windows 内存分配函数(如 HeapAlloc)与 Linux 的 malloc 在底层实现、分配策略上各有侧重。

    • 文件系统:文件路径表示上,Windows 惯用反斜杠 \,如 C:\Program Files\,而 Linux、macOS 等类 Unix 系统统一使用正斜杠 /,如 /usr/local/;文件属性、权限管理同样差异显著。

  • 编译器差异:主流编译器如 GCC(GNU Compiler Collection)、Clang、Visual C++ 对 C++ 标准支持程度参差不齐。部分新 C++ 特性,如 C++17 的结构化绑定、C++20 的模块特性,在老旧编译器版本中可能未完整实现,导致使用新特性代码无法编译。

3.2 应对策略探讨

为攻克跨平台编译难关,一系列行之有效的策略应运而生,从构建系统选型到代码架构设计,全方位助力开发者跨越平台鸿沟。

  • 使用跨平台构建系统

    • CMake:作为广泛应用的跨平台构建系统,它运用简洁且平台无关的 CMakeLists.txt 文件描述项目构建逻辑。开发者指定源文件、头文件路径、依赖库等信息,CMake 依据目标平台(Windows、Linux、macOS 等)自动生成对应平台原生构建脚本。

    • Meson:新兴的现代跨平台构建系统,采用简洁的 Meson.build 文件定义项目。凭借简洁语法与高效构建性能,快速分析项目依赖,生成优化构建指令,且与多种编译器无缝配合,支持增量构建、交叉编译等高级特性。

  • 遵循 C++ 标准:坚守 C++ 标准库与核心语言特性是基石,尽量规避特定平台扩展或非标准特性。利用 CppCheckClang-Tidy 等静态分析工具检查代码规范性,确保代码严格遵循标准,增强可移植性。

  • 抽象平台相关代码:运用分层架构设计理念,将平台特定代码封装于底层独立模块。如文件操作、网络通信、图形界面交互等功能,通过抽象基类或接口定义统一调用方式,在底层针对不同平台(Windows API、Linux 系统调用、macOS 框架)实现具体细节,上层业务逻辑仅依赖抽象层,移植时只需更替底层实现,核心逻辑不受波及。

  • 使用跨平台库

    • Qt:功能强大的跨平台 GUI(Graphical User Interface)框架,提供统一 API 涵盖窗口管理、控件绘制、事件处理等功能,代码一次编写,无需修改即可在 Windows、macOS、Linux 等多平台生成原生界面风格应用。

    • Boost:涵盖多领域的 C++ 库集合,如 Boost.Filesystem 提供统一文件操作接口,Boost.Thread 实现跨平台多线程支持,借助这些成熟库组件,避免重复造轮,巧妙规避平台底层差异陷阱。

  • 处理编译器差异:优先选用兼容性强、对 C++ 标准支持完备的编译器作为基准,如 GCC 在跨平台开发中应用广泛。针对特定平台需使用本地编译器时,借助条件编译指令(#ifdef#ifndef 等)或预处理宏,依据编译器标识选择性包含适配代码片段,确保代码在不同编译器顺利编译,行为一致。

  • 管理依赖库:跨平台开发中,精心挑选依赖库至关重要。优先考量支持多平台且维护活跃的库,如 SQLite 数据库库,具备良好跨平台特性与稳定性。借助 vcpkgConan 等跨平台库管理工具,统一依赖库安装、版本控制与链接配置流程,自动适配不同平台,降低手动管理复杂度。

四、模板元编程与泛型编程的编译处理

4.1 模板实例化机制

在 C++ 编译过程中,模板实例化是关键环节。当编译器遇到模板定义时,并不会直接生成代码,而是在模板被使用时,依据传入的具体类型参数进行实例化。以函数模板为例,如 template<typename T> T add(T a, T b) { return a + b; },当在代码中调用 add(5, 3) 时,编译器基于实参 53 的类型 int,推导出模板参数 Tint,进而生成针对 int 类型的函数代码,实现 int 型数据相加逻辑。

4.2 名称修饰与模板特化

C++ 引入诸多高级特性,如函数重载、模板等,致使同名函数或模板实例大量涌现。为区分这些同名实体,编译器采用名称修饰策略。在编译时,函数名依据其参数类型、个数、是否为常量引用等特征被编码修饰。例如,对于普通函数 int add(int a, int b) 与重载版本 double add(double a, double b),编译器可能将它们分别修饰为类似 _add_int_int_add_double_double 的内部名称,存入符号表。

模板特化与重载则进一步拓展编译期多态性。模板特化允许针对特定类型定制模板实现,分为完全特化与偏特化。完全特化如 template<> class Vector<bool> { // 针对bool型的特化实现 };,专为 bool 类型设计优化存储结构(可能采用位域节省空间)与操作逻辑,提升性能。偏特化如 template<typename T> class Vector<T*> { // 针对指针类型的偏特化实现 };,针对指针类型共性提供统一高效处理方式。

4.3 模板元编程特性

模板元编程赋予 C++ 编译期强大 “编程” 能力,其中递归模板、SFINAE(Substitution Failure Is Not An Error)与 Concepts 是核心特性。

递归模板常用于实现编译期计算,以计算阶乘为例,template<int N> struct Factorial { static const int value = N * Factorial<N - 1>::value; }; template<> struct Factorial<0> { static const int value = 1; };,通过模板实例化递归展开,在编译期算出阶乘值,供后续代码使用,避免运行时重复计算开销,提升效率。

SFINAE 是模板匹配关键规则,当模板实参替换失败时,编译器不会报错,而是尝试其他重载决议。如 template<typename T> typename T::value_type get_value(T t); template<typename T> T get_value(T t);,对 int 型变量调用 get_value,第一个模板因 intvalue_type 成员替换失败,编译器依 SFINAE 规则选用第二个模板,保障编译顺利推进。

C++20 引入的 Concepts 为模板参数约束带来革新,增强代码可读性与错误提示。例如,定义 template<typename T> concept Integral = std::is_integral_v<T>;,后续模板可使用 Integral<T> 约束参数必须为整型,如 template<Integral T> void process(T t);,使代码意图清晰,编译器能更早发现类型不符错误,优化模板编程体验。

4.4 编译模型与代码膨胀

C++ 编译模型涵盖包含编译模型与分别编译模型,二者在处理模板代码时各有千秋。包含编译模型,源文件直接 #include 模板定义,编译器每次使用模板均重新编译,虽简单直接,但在大型项目中,若多处使用同一模板,重复编译易引发代码膨胀,增加编译时间与二进制文件体积。

分别编译模型则试图缓解此问题,模板定义与声明分离,源文件仅包含声明,模板实例化延迟至链接阶段。如在头文件声明 template<typename T> class Matrix;,源文件实现 template<typename T> class Matrix { // 具体实现 };,使用处 Matrix<int> m;,编译器前期仅记录模板依赖,链接时统一实例化。但此模型增加链接复杂性,若模板实现变更,依赖它的文件需重新链接,且同样可能因不当使用引发代码膨胀。

五、结语

C++ 编译过程是一个复杂但至关重要的过程,从预处理、编译、汇编到链接,每个阶段都对最终的可执行文件产生深远影响。通过理解编译过程的每个环节,开发者可以更好地优化代码、排查错误,并提升程序的整体性能。希望本文的解析能够帮助开发者更深入地理解 C++ 编译过程,并在实际项目中应用这些知识,提升编程水平。

参考文献

  1. Adam优化器
  2. L2正则化
  3. 数据增强技术

未觉池塘春草梦,阶前梧叶已秋声。

在这里插入图片描述
学习是通往智慧高峰的阶梯,努力是成功的基石。
我在求知路上不懈探索,将点滴感悟与收获都记在博客里。
要是我的博客能触动您,盼您 点个赞、留个言,再关注一下。
您的支持是我前进的动力,愿您的点赞为您带来好运,愿您生活常暖、快乐常伴!
希望您常来看看,我是 秋声,与您一同成长。
秋声敬上,期待再会!

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

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

相关文章

【漏洞复现】NetMizer 日志管理系统 hostdelay.php 前台RCE漏洞复现

免责声明 请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。工具来自网络,安全性自测,如有侵权请联系删除。本次测试仅供学习使用,如若非法他用,与平台和本文作…

hive-sql 连续登录五天的用户

with tmp as (select 梁牧泽 as uid, 2023-03-03 as dt union allselect 梁牧泽 as uid, 2023-03-04 as dt union allselect 梁牧泽 as uid, 2023-03-05 as dt union allselect 梁牧泽 as uid, 2023-03-07 as dt union allselect 梁牧泽 as uid, 2023-03-08 as dt union allsel…

【运维】部署MKDocs

部署MKDocs obsidian 记录笔记&#xff0c;通过 mkdocs 私有化部署。 1 使用MKDocs创建笔记 创建仓库&#xff0c;安装 Material for MkDocs 和 mkdocs-minify-plugin mkdir tmp cd tmp git initpip install mkdocs-material pip install mkdocs-minify-pluginmkdocs new .2 …

Linux的进程替换以及基础IO

进程替换 上一篇草率的讲完了进程地址空间的组成结构和之间的关系&#xff0c;那么我们接下来了解一下程序的替换。 首先&#xff0c;在进程部分我们提过了&#xff0c;其实文件可以在运行时变成进程&#xff0c;而我们使用的Linux软件其实也是一个进程&#xff0c;所以进一步…

C#编写的金鱼趣味小应用 - 开源研究系列文章

今天逛网&#xff0c;在GitHub中文网上发现一个源码&#xff0c;里面有这个金鱼小应用&#xff0c;于是就下载下来&#xff0c;根据自己的C#架构模板进行了更改&#xff0c;最终形成了这个例子。 1、 项目目录&#xff1b; 2、 源码介绍&#xff1b; 1) 初始化&#xff1b; 将样…

cloudns二级免费域名python更新ipv6 dns记录

没找到api&#xff0c;托管到cloudflare也不行。就只能写代码了&#xff08;只写了更新和添加单条ipv6记录&#xff09; 需要修改的地方 请求头的cookies填自己的 data里的zone填自己的 import requests from lxml import etree host#子域名 cookies填自己的 zone自己域名的 …

机器学习作业 | 泰坦尼克号生存的预测任务

泰坦尼克号生存的预测任务 学校作业&#xff0c;我来水一水 环境&#xff1a;pycharmanaconda虚拟环境 文章目录 泰坦尼克号生存的预测任务0.环境搭建参考&#xff1a;1 目的与要求2 任务背景3 任务简介4 模型介绍1.决策树&#xff08;Decision Tree&#xff09;2.朴素贝叶斯…

【pytorch】conda安装pytorch

Step 1 打开官网&#xff1a; https://pytorch.org/get-started/locally/ 进行选择对应版本&#xff1a; 复制图中命令执行。 Step 2 验证是否安装成功。 执行&#xff1a; import torch print(torch.cuda.is_available()) print(torch.cuda.device_count()) print(torch.…

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(四)

文章目录 一、管理员角色功能实现1、添加教师功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、教师管理功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询接口实现2.3.2 后端编辑接口实现2.3.3 后端删除接口实现2.4 效果展示二、代码下…

基于16QAM的载波同步和定时同步性能仿真,采用四倍采样,包括Costas环和gardner环

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要 载波同步是…

新服务器ubuntu系统相关操作

1、查看驱动:驱动版本535.216.01能够支持cuda12.2,下面直接使用默认安装的cuda。 2、赋予用户管理员权限。 首先有超级用户(root)权限来编辑 /etc/sudoers 文件,visudo 是一个命令,用于安全地编辑 /etc/sudoers 文件。运行: sudo visudo 在 visudo 编辑器中,找到类似…

2、Bert论文笔记

Bert论文 1、解决的问题2、预训练微调2.1预训练微调概念2.2深度双向2.3基于特征和微调&#xff08;预训练下游策略&#xff09; 3、模型架构4、输入/输出1.输入&#xff1a;2.输出&#xff1a;3.Learned Embeddings(学习嵌入)1. **Token Embedding**2. **Position Embedding**3…

python 渗透开发工具之SQLMapApi Server不同IP服务启动方式处理 解决方案SqlMapApiServer外网不能访问的情况

目录 说在前面 什么是 SQLMapAPI 说明 sqlmapApi能干什么 sqlmapApi 服务安装相关 kali-sqlmap存放位置 正常启动sqlmap-api server SqlMapApi-Server 解决外网不能访问情况 说在前面 什么是sqlmap 这个在前面已经说过了&#xff0c;如果这个不知道&#xff0c;就可以…

操作系统论文导读(八):Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个

Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个关键性规范的零星任务的可调度性分析 目录 一、论文核心思想 二、基本定义 2.1 关键性指标 2.2 任务及相关参数定义 2.3 几个基础定义 三、可调度性分析 3.1 调度算法分…

技术速递|调用异步功能 - WinForms 在 .NET 9 中的未来发展

作者&#xff1a; Klaus Loeffelmann 排版&#xff1a;Alan Wang 随着 .NET 的不断发展&#xff0c;WinForms 开发者可用的工具也在不断进步&#xff0c;这使得开发更加高效且应用响应更迅速。在 .NET 9 中&#xff0c;我们很高兴引入了一系列新的异步 API&#xff0c;这些 API…

Docker-构建自己的Web-Linux系统-镜像webtop:ubuntu-kde

介绍 安装自己的linux-server,可以作为学习使用&#xff0c;web方式访问&#xff0c;基于ubuntu构建开源项目 https://github.com/linuxserver/docker-webtop安装 docker run -d -p 1336:3000 -e PASSWORD123456 --name webtop lscr.io/linuxserver/webtop:ubuntu-kde登录 …

【每日学点鸿蒙知识】箭头函数、Watch状态变量、H5获取定位数据、前后台切换、长按事件

【每日学点鸿蒙知识】箭头函数、Watch状态变量、H5获取定位数据、前后台切换、长按事件 1、HarmonyOS confirm: () > void () > { }&#xff1f; confirm: () > void () > { }是什么格式。 是一个箭头函数&#xff0c;它的类型是 () > void&#xff0c;表示…

【人工智能机器学习基础篇】——深入详解监督学习之模型评估:掌握评估指标(准确率、精确率、召回率、F1分数等)和交叉验证技术

深入详解监督学习之模型评估 在监督学习中&#xff0c;模型评估是衡量模型性能的关键步骤。有效的模型评估不仅能帮助我们理解模型在训练数据上的表现&#xff0c;更重要的是评估其在未见数据上的泛化能力。本文将深入探讨监督学习中的模型评估方法&#xff0c;重点介绍评估指…

如何使用React,透传各类组件能力/属性?

在23年的时候&#xff0c;我主要使用的框架还是Vue&#xff0c;当时写了一篇“如何二次封装一个Vue3组件库&#xff1f;”的文章&#xff0c;里面涉及了一些如何使用Vue透传组件能力的方法。在我24年接触React之后&#xff0c;我发现这种扩展组件能力的方式有一个专门的术语&am…

点进CSS选择器

CSS 1.直接在标签的style属性进行设置(行内式) //写在数据单元格td标签内的stytle&#xff0c;设置color颜色和font-size字体大小&#xff1b; <td rowspan"3" style"color: red;font-size: 12px;">Web技术与应用</td> 2.写在head标签中的…