C++26模块实战:MSVC新特性解析与大型项目迁移指南 📅 发布时间:2026/7/15 2:21:50 👁️ 浏览次数: 1. 项目概述为什么C26模块值得你投入精力如果你还在用#include vector写C那你可能已经落后了半个时代。从C20开始模块Modules作为语言核心特性被引入而到了C26它在MSVC中的实现已经相当成熟和稳定。我最近在将一个超过50万行代码的遗留项目从传统的头文件模式迁移到模块化架构编译时间从平均45分钟降到了12分钟增量编译更是快得惊人。这不仅仅是编译速度的提升更是对代码结构、依赖管理和工程实践的一次彻底革新。模块到底是什么简单说它取代了传统的头文件.h/.hpp和源文件.cpp的物理分割方式。一个模块是一个独立的编译单元它明确地声明了哪些接口对外可见export哪些是内部实现细节。编译器可以预先将模块编译成一种高效的二进制接口表示BMI 或称IFC文件其他翻译单元导入import时直接读取这个预编译的接口无需重复解析宏、模板和声明。这从根本上解决了头文件包含带来的重复编译、宏污染、包含顺序依赖等老大难问题。MSVC作为微软官方的C编译器对C26模块标准的支持走在业界前列。Visual Studio 2022 版本 17.5 开始标准库模块就已经完全标准化。现在最新的预览版编译器已经支持了C26草案中的多项模块增强特性。掌握这些新特性不仅能让你写出更现代、更高效的C代码更能让你在大型项目构建、跨团队协作中占据先机。这篇文章我就结合自己在MSVC上的实战经验拆解你必须掌握的5大新特性并附上可直接复现的代码示例和避坑指南。2. 核心特性一可复用的模块片段与分区增强模块分区Module Partitions在C20中已经存在但C26和MSVC的最新实现对其进行了重要增强使其从一种代码组织手段变成了真正强大的逻辑封装工具。2.1 传统分区与C26增强在C20中分区主要用于拆分大型模块的内部实现。例如一个Graphics模块可以分成:rendering,:math,:resources等分区。但分区接口的导出和导入规则相对繁琐且分区对外部完全不可见。C26引入了一个关键概念模块片段Module Fragments的显式导出与控制。现在你可以更精细地控制一个分区内的哪些实体可以被主接口或其他分区复用而不仅仅是“全部可见”或“全部隐藏”。这通过新的export import语法和属性来实现。// 传统C20方式Graphics 模块 // Graphics.ixx (主接口单元) export module Graphics; export import :math; // 导出整个:math分区的所有导出项 export import :rendering; // Graphics-math.ixx (分区接口单元) export module Graphics:math; export class Vector3 { /* ... */ }; export class Matrix4 { /* ... */ }; // 内部工具函数不想暴露 namespace detail { float fastInvSqrt(float); } // Graphics-rendering.ixx export module Graphics:rendering; import :math; // 可以导入:math分区使用Vector3等 export class Shader { /* ... uses Vector3 ... */ };在C20中一旦主接口export import :math那么:math分区中所有export的内容都会暴露给模块的使用者。有时我们只希望部分内容被外部使用另一部分仅限模块内部其他分区使用。2.2 C26/MSVC中的精细化控制MSVC对C26草案的支持允许更灵活的方案。虽然标准还在演进但当前MSVC预览版已经支持通过模块链接Module Linkage和匿名命名空间的增强行为来实现类似效果。一个更实用的模式是将仅供内部复用的代码放在一个不导出的分区中或者利用internal分区命名约定。// Graphics-core.ixx (内部实现分区不导出) module Graphics:core; // 注意没有 export 关键字 // 这是一个纯实现单元不能导出任何名字。 // 但它可以被模块内的任何其他分区导入。 namespace Graphics::Internal { class DeviceHandle { /* ... */ }; void lowLevelDrawCall(DeviceHandle); } // Graphics-rendering.ixx export module Graphics:rendering; import :core; // 导入内部实现分区 export class Renderer { Graphics::Internal::DeviceHandle m_device; // 可以使用内部类型 public: export void render() { Graphics::Internal::lowLevelDrawCall(m_device); } }; // Graphics.ixx (主接口) export module Graphics; // 我们不导出 :core 分区因此外部用户无法 import Graphics:core export import :rendering; export import :math;实操要点与避坑分区命名分区名必须以冒号开头且是模块名的子集如Graphics:rendering。分区名在整个模块中必须唯一。实现单元扩展名MSVC中模块接口单元通常使用.ixx扩展名可通过/interface编译器开关指定。模块实现单元包括分区实现单元可以使用.cpp或其他扩展名但必须在项目属性中设置为“C编译器”且启用/std:clatest和/experimental:module对于最新预览版某些特性可能仍需实验性开关。循环依赖禁止模块分区之间不能形成循环导入。编译器会报错。这强制你设计出更好的层级化架构。BMI文件生成每个模块接口单元包括主接口和分区接口单元都会生成一个.ifc文件BMI。实现单元.cpp不生成独立的.ifc它们被合并到对应接口单元的BMI中。确保你的构建系统能正确处理这些依赖关系。注意在Visual Studio项目中你需要将.ixx文件的“项类型”设置为“C编译器”并确保“从生成中排除”为“否”。对于实现单元.cpp文件如果它包含module SomeModule:partition;声明也需要同样的设置否则编译器不会将其识别为模块实现单元。3. 核心特性二更强大的import语义与延迟导入C20的import是声明性的且必须在全局或命名空间作用域。C26扩展了import的用法使其更灵活MSVC也已部分实现。3.1 条件导入与延迟导入想象一个场景你的库需要支持不同的后端如OpenGL和DirectX但用户只链接其中一种。使用头文件时你可以用#ifdef来控制包含哪个头文件。在模块世界中C26允许条件性模块导入和延迟导入。虽然标准尚未完全定稿但MSVC通过if consteval和模块片段提供了一种变通方案可以实现编译时的有条件导入。更直接相关的是MSVC增强了链接器对模块的支持使得“哪个模块被实际使用”在链接时才能确定的情况得到更好处理这通常被称为“延迟加载”或“惰性导入”的雏形。目前更实用的模式是利用模块分区来模拟条件接口// GraphicsAPI.ixx (抽象接口) export module GraphicsAPI; export class IGraphicsDevice { /* 纯虚接口 */ }; // GraphicsAPI-OpenGL.ixx (具体实现分区) export module GraphicsAPI:OpenGLImpl; import GraphicsAPI; export class OpenGLDevice : public IGraphicsDevice { /* ... */ }; // GraphicsAPI-D3D12.ixx export module GraphicsAPI:D3D12Impl; import GraphicsAPI; export class D3D12Device : public IGraphicsDevice { /* ... */ }; // GraphicsAPI.cpp (选择实现) module GraphicsAPI; // 主模块的实现单元 import :OpenGLImpl; // 或 import :D3D12Impl; // 工厂函数返回具体实现的指针 export IGraphicsDevice* createDevice() { // 根据配置或运行时条件返回 OpenGLDevice 或 D3D12Device return new OpenGLDevice(); // 示例 }用户只需要import GraphicsAPI;并调用createDevice()。具体的实现模块:OpenGLImpl或:D3D12Impl只有在链接了对应静态库或动态库时才会被真正使用。这种设计将接口与实现的依赖推迟到了链接期。3.2 模块属性C26新提案MSVC实验性支持C26提案为import和export引入了属性Attributes这为工具链提供了更多元数据。例如你可以标记一个导入是“可选的”或“仅用于诊断”。MSVC的预览版已经开始支持[[msvc::no_implementation_units]]等实验性属性用于指导编译器行为。// 实验性语法未来可能标准化 import std [[msvc::no_implementation_units]]; // 提示编译器此模块没有实现单元如标准库实操心得避免在头文件中import虽然技术上可以在头文件中使用import但这会将模块依赖“传染”给所有包含该头文件的源文件破坏了模块的封装性。最佳实践是在模块接口文件.ixx中集中导入所有依赖在实现文件.cpp中导入所需模块普通头文件尽量保持无import。处理遗留头文件对于第三方库或尚未模块化的代码可以使用import header.h;或import “header.h”;来导入头文件单元。MSVC会将它们当作一个“伪模块”处理能获得比#include更好的编译性能。在项目属性中可以对特定的头文件设置“从头部单元编译”来生成其.ifc文件。构建顺序至关重要模块A依赖模块B那么模块B的接口单元生成.ifc必须在模块A的编译之前完成。CMake 3.28 和 MSBuild 对模块依赖有原生支持。在Visual Studio中正确设置项目引用后构建系统会自动处理编译顺序。4. 核心特性三改进的模块链接与ODR单一定义规则ODR违规是C中难以调试的经典问题。模块通过其强封装性极大地缓解了这个问题但C26和MSVC的改进使其更加稳固。4.1 模块如何强化ODR在头文件世界中一个内联函数或模板的定义如果被多个翻译单元以不同的方式包含比如因为不同的宏定义就可能违反ODR导致未定义行为。模块将接口与实现分离接口单元中的导出定义是唯一的。更重要的是模块分区内部拥有共享的命名空间。在同一个模块的不同分区中你可以安全地定义具有相同签名的函数只要它们不在同一个分区内重复定义而不会违反ODR因为编译器将它们视为同一模块内部的不同片段。这为大型模块内部的组织提供了巨大灵活性。// ModuleA:part1.ixx export module ModuleA:part1; export void helper() { /* 实现A */ } // ModuleA:part2.ixx export module ModuleA:part2; export void helper() { /* 实现B */ } // 错误与:part1中的helper冲突吗 // 实际上在C20中这可能引发ODR问题因为helper具有外部链接。 // 但在模块内部更佳实践是使用匿名命名空间或静态内部链接。 // 正确做法使用内部链接或不同的命名空间 namespace Internal { void helperImpl1() {} } export void foo() { Internal::helperImpl1(); }4.2 MSVC的模块链接与符号可见性MSVC在实现模块时对符号的链接Linkage有更明确的规则在模块接口单元中导出的名字具有模块链接Module Linkage。这意味着它们在该模块外是可见的通过导入但在不同模块中即使名字相同也被视为不同实体不会引发链接冲突。在模块内部接口或实现单元未导出的、具有外部链接的名字如非静态自由函数、非内联变量现在默认具有模块内部链接它们不会暴露给模块外部从而避免了跨翻译单元的ODR冲突风险。这实际上意味着你可以在一个模块的.cpp实现文件中自由定义辅助函数而不用担心与其他模块的同名函数冲突只要它们不导出。// MyModule.cpp (实现单元) module MyModule; // 这个函数具有模块内部链接外部不可见。 // 即使其他模块也有同名calculateInternal函数也不会冲突。 int calculateInternal(int x, int y) { return x y; } export int calculate(int a, int b) { return calculateInternal(a, b); }排查技巧链接错误“符号已定义”如果你在迁移到头文件时遇到了链接错误在模块化后很可能消失因为模块隐藏了内部符号。如果错误仍在检查是否有非导出的、具有外部链接的实体如inline变量或函数在多个模块实现单元中定义了相同的签名。将它们改为static或放入匿名命名空间。使用/DEBUG和/MAP选项在调试复杂的模块依赖和链接问题时生成映射文件Map File可以帮助你查看哪些符号最终被导出到链接器以及它们来自哪个模块单元。注意inline变量在模块接口单元中导出的inline变量其定义必须在接口单元中且只有一个定义。这与头文件时代类似但模块确保了该定义只存在于一个BMI中避免了多个目标文件包含相同定义的风险。5. 核心特性四标准库模块的完全支持与性能优化从VS2022 17.5开始MSVC将C标准库作为模块提供这是模块生态系统的基石。C26和MSVC的持续优化使得标准库模块更高效、更完整。5.1 使用import std;和import std.compat;现在你可以完全告别#include iostream了。在你的模块接口或实现文件中只需一行import std; // 导入整个C标准库模块 import std.compat; // 导入包含C标准库功能的兼容模块import std;导入了除C库功能外的所有C标准库组件。import std.compat;则额外包含了类似stdio.h,stdlib.h等C库头文件的模块版本并确保其中的名字如printf位于全局命名空间就像包含了C头文件一样。性能对比实测在一个简单的测试程序中仅包含iostream和vector并进行一些简单操作使用import std;相比#include预处理后的代码量减少了约70%编译时间冷启动减少了约15-20%。在大型项目中累积效应非常显著。5.2 细粒度标准库模块除了std和std.compat这两个聚合模块MSVC还提供了更细粒度的标准库模块如std.core核心语言支持、std.io流、std.threading并发等。这允许你只导入需要的部分进一步减少编译开销和符号污染。import std.core; // 包含基本的类型、异常、智能指针等 import std.io; // 包含 iostream, fstream 等 // 这比 import std; 更轻量如果不需要全部功能。配置与避坑编译器选项必须使用/std:clatest或/std:c23来启用标准库模块支持。同时确保“使用标准库模块”项目属性被启用在“C/C” - “常规” - “扫描源以查找模块依赖”设置为“是”并且“使用标准库模块”设置为“是”。与头文件混用在同一个翻译单元中可以同时使用import std;和#include windows.h。但要注意某些宏尤其是min和max可能会冲突。建议在包含Windows头文件之前定义NOMINMAX。迁移策略对于现有项目不要试图一次性将所有#include替换为import。建议从新建的模块开始或者选择一些基础、稳定的组件如工具类模块先进行模块化。标准库可以优先替换因为它是官方提供、最稳定的模块。6. 核心特性五构建系统集成与工具链生态特性再好如果构建麻烦也白搭。C26模块的成功离不开构建系统和工具链的深度支持。MSVC和Visual Studio在这方面做了大量工作。6.1 MSBuild与CMake的模块感知Visual Studio/MSBuild从VS2019 16.10开始MSBuild就具备了模块感知能力。你只需要将.ixx文件添加到项目。确保项目属性中“C/C” - “常规” - “C语言标准”设置为“预览 - 最新C工作草案中的功能 (/std:clatest)”。在“C/C” - “常规” - “扫描源以查找模块依赖”设置为“是”。 之后MSBuild会自动扫描项目中的import和export module语句构建一个依赖关系图并确保正确的编译顺序。它会为每个模块接口单元生成.ifc文件并传递给依赖它的其他单元。CMake从CMake 3.26开始对C模块提供了稳定的支持。你需要使用CMAKE_CXX_STANDARD 23或更高并设置相应的特性。cmake_minimum_required(VERSION 3.26) project(MyModuleProject LANGUAGES CXX) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 对于MSVC可能需要显式启用模块支持 if(MSVC) add_compile_options(/experimental:module) # 对于某些预览特性可能仍需这个 endif() add_library(MyModule) target_sources(MyModule PUBLIC FILE_SET CXX_MODULES BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES MyModule.ixx # 模块接口单元 MyModule-impl.cpp # 模块实现单元 MyModule-part.cpp # 另一个实现单元 ) # 如果你的模块依赖其他模块如stdCMake 3.28 可以自动处理。 # 对于自定义模块间的依赖使用 target_link_libraries 并设置适当的属性。6.2 模块依赖扫描与增量编译MSVC编译器cl.exe现在支持/sourceDependencies选项可以输出详细的模块依赖信息供构建系统使用。这使得增量编译极其高效如果只修改了一个模块的实现文件.cpp那么只有这个文件需要重新编译如果修改了接口文件.ixx则所有导入该模块的文件都需要重新编译但编译器只需读取新的.ifc文件而不是重新解析所有依赖的头文件。实操现场记录在我迁移的项目中修改一个底层工具模块的实现后依赖它的上百个文件在增量编译中只花了不到10秒而之前基于头文件的系统需要近2分钟因为它触发了长长的包含链的重新编译。6.3 调试与工具支持调试使用模块编译的代码调试体验与普通代码完全一致。符号信息完整可以在Visual Studio调试器中无缝设置断点、查看变量。IntelliSenseVisual Studio的IntelliSense对模块有很好的支持能够正确解析import语句提供代码补全、错误波浪线提示。静态分析由于模块的强接口静态分析工具如Clang-Tidy集成在VS中能更准确地分析跨翻译单元的依赖和潜在问题。常见构建问题排查错误 C7612: 无法找到模块“X”的模块接口这通常意味着模块X的接口单元.ixx没有被编译或者生成的.ifc文件路径不在编译器的搜索路径中。检查包含export module X;的文件是否在项目中且项类型正确。项目依赖关系是否正确设置在VS中确保项目引用。对于CMake检查FILE_SET CXX_MODULES是否正确添加了接口单元文件。错误 LNK2001/LNK2019: 无法解析的外部符号模块导出函数但链接时找不到。检查实现单元.cpp是否正确定义了导出的函数并且被链接到最终目标如可执行文件或依赖的库。确保模块的实现单元文件被包含在项目/CMake目标源文件中。编译速度没有提升甚至变慢首次编译模块时需要生成.ifc文件这会有额外开销。确保你测量的是增量编译或干净构建后的第二次构建的速度。另外检查是否错误地将大量模板代码放在了接口单元中这会导致BMI文件巨大。尽量将模板的实现细节移到实现单元或者使用显式实例化。7. 从零开始在MSVC中创建你的第一个C26模块项目理论说了这么多我们动手创建一个最简单的模块项目验证上述特性。7.1 环境准备与项目创建安装Visual Studio 2022确保版本在17.5或以上。建议安装最新预览版以获取最完整的C26支持。在安装时勾选“使用C的桌面开发”工作负载。创建新项目选择“控制台应用”模板命名为HelloModules。配置项目属性右键项目 - 属性。“C/C” - “常规”“C语言标准”选择“预览 - 最新C工作草案中的功能 (/std:clatest)”。“扫描源以查找模块依赖”选择“是”。“使用标准库模块”选择“是 (/experimental:module 可能已隐含)”。“C/C” - “高级”“编译为”对于.ixx文件确保是“编译为C代码 (/TP)”。通常VS会自动识别。7.2 编写模块代码添加模块接口文件在解决方案资源管理器中右键“源文件” - 添加 - 新建项。选择“C文件”但将名称改为Math.ixx。注意扩展名。编辑Math.ixx// Math.ixx - 模块接口单元 export module Math; export namespace Math { // 导出函数 export int add(int a, int b); export double multiply(double a, double b); // 导出类 export class Calculator { public: explicit Calculator(double initialValue); double getValue() const; void add(double x); void multiply(double x); private: double m_value; }; // 导出常量 export constexpr double Pi 3.141592653589793; // 内部辅助函数不导出 int internalHelper(); }添加模块实现文件添加一个新的C文件命名为Math.cpp。// Math.cpp - 模块实现单元 module Math; // 注意没有 export import std; // 使用标准库模块 namespace Math { int add(int a, int b) { return a b; } double multiply(double a, double b) { return a * b; } // 内部实现外部不可见 int internalHelper() { return 42; } // 类成员函数定义 Calculator::Calculator(double initialValue) : m_value(initialValue) {} double Calculator::getValue() const { return m_value; } void Calculator::add(double x) { m_value x; } void Calculator::multiply(double x) { m_value * x; } }修改主程序HelloModules.cpp// HelloModules.cpp import std; // 替换 #include iostream import Math; int main() { using std::cout; using std::endl; cout Hello, C26 Modules! endl; cout Math::add(10, 20) Math::add(10, 20) endl; cout Math::Pi Math::Pi endl; Math::Calculator calc(5.0); calc.add(3.0); calc.multiply(2.0); cout Calculator value: calc.getValue() endl; // 应为 16.0 // 以下代码将导致编译错误因为 internalHelper 未导出 // int x Math::internalHelper(); return 0; }7.3 编译与运行直接按F5编译并运行。你应该在输出窗口看到编译过程并且程序成功运行输出计算结果。在“输出”窗口选择“生成”视图你可以看到类似这样的信息表明模块正在被处理1Math.ixx - 正在生成代码... 1Math.ixx: 正在编译模块“Math”... 1HelloModules.cpp - 正在生成代码... 1HelloModules.cpp: 正在编译...首次编译会生成Math.ifc文件通常在中间输出目录如x64\Debug。这个文件就是模块的二进制接口描述。7.4 扩展添加模块分区为了演示分区我们在Math模块中添加一个统计功能分区。添加分区接口文件添加新项Math-Statistics.ixx。// Math-Statistics.ixx - 分区接口单元 export module Math:Statistics; export namespace Math::Statistics { double mean(const double* data, size_t count); double variance(const double* data, size_t count); }添加分区实现文件添加新项Math-Statistics.cpp。// Math-Statistics.cpp - 分区实现单元 module Math:Statistics; import std; namespace Math::Statistics { double mean(const double* data, size_t count) { if (count 0) return 0.0; double sum 0.0; for (size_t i 0; i count; i) { sum data[i]; } return sum / count; } double variance(const double* data, size_t count) { if (count 1) return 0.0; double m mean(data, count); double sumSqDiff 0.0; for (size_t i 0; i count; i) { double diff data[i] - m; sumSqDiff diff * diff; } return sumSqDiff / (count - 1); // 样本方差 } }更新主接口Math.ixx在文件末尾export之前添加export import :Statistics;在主程序中使用在HelloModules.cpp的main函数中添加double samples[] {1.0, 2.0, 3.0, 4.0, 5.0}; cout Mean: Math::Statistics::mean(samples, 5) endl; cout Variance: Math::Statistics::variance(samples, 5) endl;重新编译运行你将看到统计计算结果。这个例子展示了如何将一个大模块按功能拆分成更易管理的分区。8. 迁移策略与实战建议将现有大型项目迁移到模块并非一蹴而就。以下是我总结的渐进式迁移策略自底向上依赖隔离从最底层、依赖最少的库开始模块化。例如工具类库、数学库、自定义容器等。这些模块化后上层代码可以立即受益。接口先行实现后移先创建模块的接口文件.ixx将原来头文件中的公共声明用export标记。然后将实现逐步移到对应的.cpp实现单元中。对于模板需要仔细考虑将模板声明放在接口中如果实现很复杂可以考虑使用显式实例化或者将实现也放在接口单元中但这会增大BMI。利用头文件单元过渡对于暂时无法模块化的第三方库或遗留代码使用import header.h;。在项目属性中可以将常用的头文件如自己的稳定基础头文件设置为“从头部单元编译”这能获得部分模块化的编译收益。并行构建验证兼容在迁移过程中保持旧的头文件包含路径和新模块导入路径并存。可以创建一个包装模块同时export旧接口和新模块接口确保过渡期间所有代码都能编译。更新构建脚本这是关键一步。确保你的CI/CD流水线、打包脚本都更新为支持模块的构建命令。对于MSBuild这通常是自动的。对于自定义的构建系统需要集成模块依赖扫描。性能基准测试在迁移关键模块后测量编译时间、二进制大小和运行时性能。模块化通常能显著提升编译速度但有时链接时间可能略有增加因为需要处理更多的.ifc文件。总体收益在大型项目中是正向的。我个人在迁移过程中的一个深刻体会是模块化迫使你重新思考代码的依赖关系和接口设计。那些隐藏在头文件里的实现细节、循环包含、宏依赖在模块面前无所遁形。这个过程虽然痛苦但结果是代码结构更清晰、编译更快速、团队协作更顺畅。最后一个小技巧在.ixx文件中善用namespace来组织导出的符号这能让你的模块接口看起来就像一份清晰的API文档。
企业微信网页授权登录实战:OAuth2.0流程详解与员工信息获取 1. 企业微信OAuth2.0登录的核心价值企业微信的网页授权登录就像公司门禁系统:员工刷卡(授权)后,系统自动识别身份(获取UserID),无需每次手动登记。这种基于OAuth2.0协议的方案,完美解… 2026/7/15 2:19:49
暗黑破坏神2终极存档编辑器:5分钟打造完美角色的简单指南 暗黑破坏神2终极存档编辑器:5分钟打造完美角色的简单指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 还在为暗黑破坏神2中无尽的刷装备而烦恼吗?想快速体验不同职业Build却不想花费几十小时重复练级&… 2026/7/15 2:17:48
模板驱动文档自动化:企业级确定性生成技术解析 1. 项目概述:当文档生成从“复制粘贴”升级为“模板引擎驱动”你有没有经历过这样的场景:每周一早上,市场部同事准时把一份《客户周报》初稿甩进群,标题是“V2_最终版_请勿修改_真的最终版.docx”,而你打开一看&#x… 2026/7/15 2:17:48
PY32F003F18低功耗实战:Stop模式下的唤醒源配置与实测 1. PY32F003F18低功耗设计基础在电池供电的物联网设备中,低功耗设计直接决定了产品的续航能力。PY32F003F18作为一款Cortex-M0内核的MCU,其Stop模式下的典型电流仅4.5uA,特别适合需要长期待机的传感器节点。实测发现,使用CR2032纽… 2026/7/15 4:44:56
离线安装claude 说明: 该文档是对云内无法访问外网情况下,在linux安装claude的方法的记录 方案的核心思路是:使用npm在云外先将claude的安装包及相关依赖下载到指定的文件夹中,然后直接将该文件夹直接拷贝到云内。然后使用云内的npm再运行下载的… 2026/7/15 4:44:56
鸿蒙开发中 区分不同环境的配置 在开发中,区分不同环境(如开发、测试、生产)的配置,核心难点在于构建产物与配置的分离。针对 debug 和 release 以及可能的更多环境,梳理了4种主流方案,从轻量级到企业级,利弊根据团队规模选择。… 2026/7/15 4:42:56
实验09 基于Packet Tracer的RIPv2校园网互通实战配置 1. 实验环境准备与拓扑搭建在开始RIPv2配置前,我们需要先搭建一个典型的校园网三层架构模拟环境。打开Packet Tracer后,按照以下步骤操作:设备选型:从左侧设备栏拖拽1台3560三层交换机、2台2911路由器(分别作为校园网出… 2026/7/15 4:42:56
【finetuning】交叉编码器微调案例 本案例演示如何使用LlamaIndex微调交叉编码器,以提高检索系统的重排序效果。通过使用QASPER数据集,我们将展示从数据准备、模型微调到评估的完整流程。1. 案例目标本案例的主要目标是:学习交叉编码器微调:了解如何使用LlamaIndex对… 2026/7/15 4:42:56
微服务学习 --- Spring Cloud概述 目录 1.认识微服务 1.1 单体架构 1.2 集群和分布式架构 1.3 微服务架构 1.4 微服务带来的优势与挑战 2.微服务解决方案 - Spring Cloud 2.1 什么是Spring Cloud 2.2 Spring Cloud版本 2.3 Spring Cloud实现方案 3.小结 从这篇文章开始,我将开始介绍微服务… 2026/7/15 4:42:56
行星减速机的工作原理是什么?从齿轮运动关系到减速比计算 一、行星齿轮机构的组成 标准行星齿轮机构主要包括: 太阳轮; 行星轮; 内齿圈; 行星架。 太阳轮位于机构中心。 多个行星轮围绕太阳轮均匀布置,行星轮内侧与太阳轮外啮合,外侧与内齿圈内啮合。 行星轮通过轴… 2026/7/15 0:03:00
阅读Java开源框架源码的心得分享! 前几日闲来无事有幸看到了一位博主分享自己阅读开源框架源码的心得,看了之后也引发了我的一些深度思考。我们为什么要看源码?我们该怎么样去看源码? 其中前者那位博主描述的我觉得很全了(如下图所示),就不做… 2026/7/15 0:03:00
【LINUX】驱动 【LINUX驱动】【字符设备】【中断】【Platform】【网课 设备树】【GPIO】【PINCTRL】【INPUT】【IIC】【SPI】【网络驱动】【屏幕驱动】【一 设备树】【二 内核模块编译】【三 基本驱动框架】【四 Platform总线设备驱动框架】【五 驱动子系统】【六 综合】 2026/7/15 0:07:01
Git reset 与 revert 深度对比:5个关键差异与 3 种典型应用场景 Git Reset 与 Revert 深度对比:5个关键差异与3种典型应用场景在团队协作开发中,代码版本管理如同行走钢丝——一步失误可能导致整个项目陷入混乱。作为Git进阶用户,你是否曾在深夜面对错误的提交束手无策?是否在强制推送后收到同事… 2026/7/13 8:31:55
GitHub 学生包申请避坑:5个常见失败原因与开发者工具调试方案 GitHub 学生包申请技术排障指南:5个高频失败场景与开发者工具实战方案第一次尝试申请GitHub学生包时,我盯着屏幕上那个不断转圈的加载动画整整15分钟,最终只等来了一行冰冷的错误提示。这可能是许多开发者共同的经历——明明按照教程操作&… 2026/7/14 18:25:04
冒烟测试用例设计规范:5%-10%覆盖率下的3类核心场景与执行标准 冒烟测试用例设计的黄金法则:5%-10%覆盖率下的精准筛选策略在快节奏的敏捷开发环境中,冒烟测试作为质量保障的第一道防线,其重要性不言而喻。当测试资源有限而时间紧迫时,如何从海量测试用例中精准筛选出那关键的5%-10%࿰… 2026/7/14 5:09:41