跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • Online Tools
  • 用户
  • 群组
折叠
品牌标识

D2Learn Forums

mcpp-team

mcpp社区团队

私有

帖子


  • GCC 16 上手初体验:环境配置、默认 C++20、模块化、诊断增强和 C++26 反射
    SPeakS SPeak

    GCC 16 上手初体验:环境配置、默认 C++20、模块化、诊断增强和 C++26 反射

    从去年发布GCC 15.1 并支持 import std开始, 我的新项目也全面转向C++23 + 模块化 (踩了不少坑 [逃]). 而最近几天 GCC 16.1 也正式发布了, 这篇文章就来初步的上手体验一下.

    主要内容包括:

    • 0.GCC 16 环境配置
    • 1.默认标准: 从C++17升级到C++20, 正式进入C++2x时代
    • 2.模块化: 有一定优化, 但任处于实验性支持阶段 (悲)
    • 3.代码诊断和静态分析增强
    • 4.C++ 26 反射实验性支持
    • 5.总结及相关链接

    0. 环境配置 (Linux)

    安装GCC 16可以选择按官方文档从源码进行构建 GCC WIKI 或 直接使用xlings工具安装预构建版本(注: 该方式有个好处不污染系统环境)

    安装xlings包管理工具

    curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/refs/heads/main/tools/other/quick_install.sh | bash
    source ~/.bashrc # 或重新打开一次控制台
    xlings -h
    

    xlings工具安装后, 创建隔离环境并安装gcc 16

    xlings subos new gcc-test
    xlings subos use gcc-test
    xlings install gcc@16.1.0 -y
    gcc --version
    

    2026-05-04_22-10.png

    1.默认标准: 从 C++17 升级到 C++20, 正式进入 C++2x 时代

    GCC 16 的一个关键变化是: C++ 编译默认标准从 GNU++17 变成 GNU++20。不用额外再写 -std=c++20 也能编译下面的程序了:

    #include <iostream>
    
    consteval int answer() {
        return 16;
    }
    
    int main() {
        std::cout << "__cplusplus=" << __cplusplus
                  << ", consteval=" << answer() << '\n';
    }
    

    编译运行:

    g++ cpp20-default.cpp -o cpp20-default
    ./cpp20-default
    

    输出:

    __cplusplus=202002, consteval=16
    

    如果显式退回 C++17:

    g++ -std=c++17 cpp20-default.cpp -o cpp17-check
    

    会报错:

    t.cpp:3:1: error: 'consteval' does not name a type; did you mean 'constexpr'?
        3 | consteval int answer() {
          | ^~~~~~~~~
          | constexpr
    

    默认标准的改变, 不仅仅只是帮我们省了-std=c++20,而是默认构建行为的改变 会加速C++ 2x时代生态的发展

    2.模块化: 有一定优化, 但任处于实验性支持阶段

    模块化早在C++20就发布, 他的目标是想解决 C++ 头文件模型长期存在的问题: 重复解析、宏污染、包含顺序敏感、接口和实现边界不够清晰。在工程方面他对C++的影响是颠覆性的, 但是由于历史/兼容性/复杂度等多方面原因导致, GCC 16 的默认标准虽然是 GNU++20,但 modules 支持仍然是实验性的,所以GCC 16对模块化爱好者来说只能算波澜不惊

    只不过, GCC16 还是有在模块化做了一些工作的

    • 修复了一些模块化的bug
    • 新增 --compile-std-module,用于更方便地构建标准库相关模块和 header unit

    其中 --compile-std-module 的增加 更方便大家体验模块化和import std, 避免了之前连一个hello world级别的main.cpp编译都要分几步的情况(有时候还有问题), 所以这也算是一大进步 - 现在可以像下面一样一键编译 import std 的程序了

    // main.cpp
    import std;
    
    int main() {
        std::println("{}", 42);
    }
    

    编译:

    g++ -std=c++23 -fmodules --compile-std-module main.cpp -o app
    ./app
    

    3. 诊断增强: 错误信息结构化 + 编译期静态代码分析

    C++ 报错经常被吐槽,不是因为编译器不知道哪里错了,而是因为错误链太长,人很难从一堆候选函数、模板实例化和类型展开里看出主线。

    GCC 16 的一个明显变化是,部分 C++ 错误信息开始用层级结构展示。例如这个声明和定义不一致的例子:

    class Foo {
    public:
        void test(int i, int j, void *ptr, int k);
    };
    
    void Foo::test(int i, int j, const void *ptr, int k) {
    }
    
    int main() {
        return 0;
    }
    

    编译:

    g++ diagnostics-mismatch.cpp
    

    GCC 16 会把候选函数和参数差异分层展示,核心信息大致是:

    error: no declaration matches 'void Foo::test(int, int, const void*, int)'
      - there is 1 candidate
        - candidate is: 'void Foo::test(int, int, void*, int)'
          - parameter 3 of candidate has type 'void*'
          - which does not match type 'const void*'
    

    这比以前只告诉你 找不到匹配声明 更有用,它一定程度指出了候选是谁、哪里不一致、哪一个参数出了问题。

    甚至还能生成更适合浏览器查看的诊断html页面:

    g++ diagnostics-mismatch.cpp \
      -fdiagnostics-add-output=experimental-html
    

    2026-05-04_22-55.png

    如果想给 CI、IDE 或代码扫描平台使用,可以生成 SARIF:

    g++ diagnostics-mismatch.cpp \
      -fdiagnostics-format=sarif 
    

    这个的优化, 不仅 报错更容易看了,而且后面可能会影响工具链体验。编译器不再只是把错误打印到终端,而是可以把结构化诊断交给网页、编辑器、代码审查和静态分析系统。

    配合上 -fanalyzer 的能力。它是 GCC 自带的静态分析能力。如果加上 -Werror 体验就有点类似Rust的严格编译期检查功能

    看一个 use-after-delete:

    #include <iostream>
    
    int main() {
        int *p = new int(42);
        delete p;
        std::cout << *p << "\n";
    }
    

    编译:

    g++ -std=c++20 -fanalyzer analyzer-uaf.cpp
    

    GCC 16 会给出类似警告:

    warning: use after 'delete' of 'p' [CWE-416] [-Wanalyzer-use-after-free]
    

    6ac11e44-be1d-4668-bd20-b4243eb62f81-image.png

    4. C++26 特性: Reflection / 反射

    GCC 16 实现了若干 C++26 特性,这里简单试一试

    -std=c++26 -freflection
    

    以一个简单的结构体为例, 看看 C++26反射 的功能:

    #include <iostream>
    #include <meta>
    #include <string_view>
    
    struct User {
        int id;
        double score;
    };
    
    consteval std::size_t field_count() {
        auto fields = std::meta::nonstatic_data_members_of(
            ^^User,
            std::meta::access_context::unchecked()
        );
        return fields.size();
    }
    
    consteval std::string_view field_name(std::size_t index) {
        auto fields = std::meta::nonstatic_data_members_of(
            ^^User,
            std::meta::access_context::unchecked()
        );
        return std::meta::identifier_of(fields[index]);
    }
    
    consteval std::string_view field_type(std::size_t index) {
        auto fields = std::meta::nonstatic_data_members_of(
            ^^User,
            std::meta::access_context::unchecked()
        );
        return std::meta::display_string_of(std::meta::type_of(fields[index]));
    }
    
    int main() {
        constexpr auto type_name = std::meta::display_string_of(^^User);
    
        std::cout << type_name << " has " << field_count() << " fields\n";
        std::cout << field_name(0) << ": " << field_type(0) << '\n';
        std::cout << field_name(1) << ": " << field_type(1) << '\n';
    }
    

    编译运行:

    g++ -std=c++26 -freflection reflection-user.cpp -o reflection-user
    ./reflection-user
    

    输出:

    User has 2 fields
    id: int
    score: double
    

    这里的 ^^User 是对 User 这个结构体类型做静态反射,std::meta::display_string_of 可以拿到类型的显示名。std::meta::nonstatic_data_members_of 则能拿到结构体的非静态数据成员列表,再通过 identifier_of 和 type_of 分别取得成员名和成员类型。

    C++ 代码可以在编译期拿到结构体自身的字段信息。这个功能对 序列化、ORM、RPC、命令行参数解析、UI 绑定、测试生成等大量现在依赖宏、模板技巧或外部代码生成的场景 有重要影响

    5. 总结

    GCC 16.1.0 感觉最核心的就是默认标准从C++17变成了C++20, 某种意义上也算正式迈入C++2x时代了, 下面是一些个人感觉

    • 1.默认 C++ 标准从 GNU++17 变成 GNU++20。能进一步加速C++生态进入C++2x的时代
    • 2.C++20 modules特性 在 GCC 16 里只是做了部分优化, 相比GCC 15.1.0引入import std来说, 没有特别惊喜
    • 3.诊断输出更结构化了。嵌套错误、HTML、SARIF 会让编译器错误更适合教学、CI 和 IDE 集成。
    • 4.C++26 Reflection 已经可以初步尝试。对于个人项目可以上手用一用 (但可能存在很多潜在的坑)

    我个人是比较关注模块化的进展, 总体来说GCC16虽然模块化特性上没有过多惊喜, 但在import std之后, 模块化算是已经初步可以在项目里尝试的水平了, 并且我们 mcpp-community 现代C++爱好者社区 已经在 模块化的 项目/库的 工程化、包管理、工具链 等方面有一定的探索, 欢迎感兴趣的朋友加入讨论

    • 社区Github主页: https://github.com/mcpp-community
    • C++23模块化项目: https://github.com/openxlings/xlings
    • C++23模块化库: https://github.com/mcpplibs

    相关链接

    • xlings: https://github.com/openxlings/xlings
    • mcpp-community: https://github.com/mcpp-community
    • GCC 16.1 Released: https://gcc.gnu.org/pipermail/gcc-announce/2026/000190.html
    • GCC 16 Release Series: Changes, New Features, and Fixes: https://gcc.gnu.org/gcc-16/changes.html
    • GCC 16.1.0: https://sourceware.org/pub/gcc/releases/gcc-16.1.0/

  • 请教如何自定义异常
    SPeakS SPeak
    class myException : public std::exception {
    private:
        std::string _msg;
    public:
        myException(const char* message) noexcept : _msg(message) {}
        
        const char* what() const noexcept override {
            return _msg.c_str();
        }
    };
    

  • 请教如何自定义异常
    SPeakS SPeak

    就你上面写的就可以啊


  • 请教如何自定义异常
    SPeakS SPeak

    const char * msg; 指针可能会关联到外部对象(不可预期的生命周期), 可以使用 std::string 自己持有对象, 确保生命周期安全. 对关于 __cow_string 这个是 内部实现的 字符串的写时复制 机制, 可以不用管

    可能的风险点

    {
        std::string localVar = "Hi, I'm local var";
        throw myException(localVar.c_str());  // localVar 出作用域 会析构, 可能会导致msg指向无效内存
    }
    
    • https://gcc.gnu.org/onlinedocs/gcc-13.1.0/libstdc++/api/a00605_source.html

  • [windows系统][环境配置] d2x命令好像无法使用?
    SPeakS SPeak

    可以用最新版本, 目前迁移的最新版本已经可以用了, 用readme里的新的安装命令 进行安装替换老版本, 这个问题应该就解决了

    https://github.com/d2learn/xlings


    image.png


  • xlings安装完成,但是项目安装提示失败
    SPeakS SPeak

    @sleepyiang 找到原因, 这个时项目里d2x buildtools的bug
    现在已经修复了

    • https://github.com/mcpp-community/d2mcpp/pull/40

    可以使用 d2x install d2mcpp 获取最新的项目 再尝试尝试

    注: 应该不是上面说的版本原因


  • [windows系统][环境配置] d2x命令好像无法使用?
    SPeakS SPeak

    @Mudrock-JO 尝试 xlings install d2x@0.1.3 先获取工具

    然后更新一下 重新用 d2x install d2mcpp 获取项目并配置环境


  • dx2命令无效
    SPeakS SPeak

    具体参考

    http://forum.d2learn.org/post/774

    e0284a32-24d0-4bd1-98a7-df45b10c84e5-image.png


  • xlings安装完成,但是项目安装提示失败
    SPeakS SPeak

    @sleepyiang 尝试换成 0.1.2版本 xlings install d2x@0.1.2 -y --use


  • dx2命令无效
    SPeakS SPeak

    @SPeak 如果能用的话 使用 xlings install d2x@0.1.3 -y 安装一下 d2x

成员列表

SPeakS SPeak
MoYingJiM MoYingJi
FrozenLemonTeeF FrozenLemonTee
  • 登录

  • 没有帐号? 注册

  • 登录或注册以进行搜索。
d2learn forums Powered by NodeBB
  • 第一个帖子
    最后一个帖子
0
  • 版块
  • 最新
  • 标签
  • 热门
  • Online Tools
  • 用户
  • 群组