You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于C++20模块的项目中使用windows.h时是否仍需预编译头?

C++20模块与预编译头:处理windows.h的最佳实践

针对你在VS2022中使用C++20模块时遇到的windows.h重复编译问题,直接给出明确结论与可行方案:

你的核心误解:全局模块片段的编译行为

你之前认为全局模块片段中的头文件会仅编译一次,这个理解有误。每个包含全局模块片段的翻译单元(TU),都会独立处理其中的#include内容。也就是说,若你有10个模块实现文件都在全局模块片段里#include <windows.h>,默认情况下windows.h会被编译10次,这确实会带来可观的编译开销。

预编译头(PCH)与模块的兼容性:不用急着禁用

VS2022完全支持在模块项目中配合使用预编译头,只要配置正确:

  • 把<windows.h>放到你的预编译头文件(比如pch.h)中;
  • 在每个模块实现文件的全局模块片段最开头,先#include "pch.h",再写其他内容:
    // ModuleA.cpp
    module;
    
    #include "pch.h" // 这里包含了windows.h
    
    module ModuleA;
    
    void Initialize() {
       // 代码...
    }
    

这样每个翻译单元都会复用预编译头的编译结果,避免重复编译windows.h。注意:预编译头文件本身不能包含任何模块声明(比如module;或module X;),必须是纯头文件内容。

更符合模块理念的优化方案:封装windows.h为私有模块

如果想彻底摆脱预编译头的依赖,同时解决windows.h的重复编译问题,推荐把windows.h封装成一个私有模块:

  1. 创建一个模块接口文件(比如Win32Dependencies.ixx):
    module;
    
    #include <windows.h>
    
    module Win32Dependencies;
    export {}; // 不需要导出任何内容,只需要把windows.h的类型导入到模块作用域
    
  2. 在其他需要用到DWORD、APIENTRY等类型的模块接口或实现文件中,直接导入这个模块:
    // ModuleA.ixx
    import Win32Dependencies;
    
    export module ModuleA;
    
    export void Initialize() {
        DWORD dw = 0; // 直接识别类型
        // 代码...
    }
    

这样整个项目中windows.h只会被编译一次,所有依赖它的模块都通过导入Win32Dependencies来获取所需类型,既符合C++20模块的设计思路,又彻底解决了重复编译问题。

额外优化:VS的外部头文件标记

如果你既不想用PCH也不想封装模块,可以给windows.h加上VS的外部头文件标记:

  • 在项目属性中,把windows.h所在的路径添加到/external:I选项中;
  • 开启/external:W0选项,让编译器对这类头文件做编译缓存优化,减少重复编译的时间开销。

内容的提问来源于stack exchange,提问作者Danik-A

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:55:09