<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Topics tagged with gun]]></title><description><![CDATA[A list of topics that have been tagged with gun]]></description><link>http://forum.d2learn.org/tags/gun</link><generator>RSS for Node</generator><lastBuildDate>Mon, 04 May 2026 21:47:34 GMT</lastBuildDate><atom:link href="http://forum.d2learn.org/tags/gun.rss" rel="self" type="application/rss+xml"/><pubDate>Invalid Date</pubDate><ttl>60</ttl><item><title><![CDATA[GCC 16 上手初体验：环境配置、默认 C++20、模块化、诊断增强和 C++26 反射]]></title><description><![CDATA[<h1>GCC 16 上手初体验：环境配置、默认 C++20、模块化、诊断增强和 C++26 反射</h1>
<p dir="auto">从去年发布GCC 15.1 并支持 <code>import std</code>开始, 我的新项目也全面转向<code>C++23 + 模块化</code> (踩了不少坑 [逃]). 而最近几天 GCC 16.1 也正式发布了, 这篇文章就来初步的上手体验一下.</p>
<p dir="auto">主要内容包括:</p>
<ul>
<li>0.GCC 16 环境配置</li>
<li>1.默认标准: 从C++17升级到C++20, 正式进入C++2x时代</li>
<li>2.模块化: 有一定优化, 但任处于实验性支持阶段 (悲)</li>
<li>3.代码诊断和静态分析增强</li>
<li>4.C++ 26 反射实验性支持</li>
<li>5.总结及相关链接</li>
</ul>
<h2>0. 环境配置 (Linux)</h2>
<p dir="auto">安装GCC 16可以选择按官方文档从源码进行构建 <a href="https://gcc.gnu.org/wiki/InstallingGCC" rel="nofollow ugc">GCC WIKI</a> 或 直接使用xlings工具安装预构建版本(注: 该方式有个好处不污染系统环境)</p>
<p dir="auto"><code>安装xlings包管理工具</code></p>
<pre><code class="language-bash">curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/refs/heads/main/tools/other/quick_install.sh | bash
source ~/.bashrc # 或重新打开一次控制台
xlings -h
</code></pre>
<p dir="auto"><code>xlings工具安装后, 创建隔离环境并安装gcc 16</code></p>
<pre><code class="language-bash">xlings subos new gcc-test
xlings subos use gcc-test
xlings install gcc@16.1.0 -y
gcc --version
</code></pre>
<p dir="auto"><img src="/assets/uploads/files/1777910290747-2026-05-04_22-10.png" alt="2026-05-04_22-10.png" class=" img-fluid img-markdown" /></p>
<h2>1.默认标准: 从 C++17 升级到 C++20, 正式进入 C++2x 时代</h2>
<p dir="auto">GCC 16 的一个关键变化是: C++ 编译默认标准从 GNU++17 变成 GNU++20。不用额外再写 <code>-std=c++20</code> 也能编译下面的程序了:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;

consteval int answer() {
    return 16;
}

int main() {
    std::cout &lt;&lt; "__cplusplus=" &lt;&lt; __cplusplus
              &lt;&lt; ", consteval=" &lt;&lt; answer() &lt;&lt; '\n';
}
</code></pre>
<p dir="auto">编译运行:</p>
<pre><code class="language-bash">g++ cpp20-default.cpp -o cpp20-default
./cpp20-default
</code></pre>
<p dir="auto">输出:</p>
<pre><code class="language-text">__cplusplus=202002, consteval=16
</code></pre>
<p dir="auto">如果显式退回 C++17:</p>
<pre><code class="language-bash">g++ -std=c++17 cpp20-default.cpp -o cpp17-check
</code></pre>
<p dir="auto">会报错:</p>
<pre><code class="language-cpp">t.cpp:3:1: error: 'consteval' does not name a type; did you mean 'constexpr'?
    3 | consteval int answer() {
      | ^~~~~~~~~
      | constexpr
</code></pre>
<p dir="auto">默认标准的改变, 不仅仅只是帮我们省了<code>-std=c++20</code>，而是默认构建行为的改变 会加速C++ 2x时代生态的发展</p>
<h3>2.模块化: 有一定优化, 但任处于实验性支持阶段</h3>
<p dir="auto">模块化早在C++20就发布, 他的目标是想解决 C++ 头文件模型长期存在的问题: 重复解析、宏污染、包含顺序敏感、接口和实现边界不够清晰。在工程方面他对C++的影响是颠覆性的, 但是由于历史/兼容性/复杂度等多方面原因导致, GCC 16 的默认标准虽然是 GNU++20，但 modules 支持仍然是实验性的，所以GCC 16对模块化爱好者来说只能算波澜不惊</p>
<p dir="auto">只不过, GCC16 还是有在模块化做了一些工作的</p>
<ul>
<li>修复了一些模块化的bug</li>
<li>新增 <code>--compile-std-module</code>，用于更方便地构建标准库相关模块和 header unit</li>
</ul>
<p dir="auto">其中 <code>--compile-std-module</code> 的增加 更方便大家体验模块化和<code>import std</code>, 避免了之前连一个hello world级别的main.cpp编译都要分几步的情况(有时候还有问题), 所以这也算是一大进步 - 现在可以像下面一样一键编译 <code>import std</code> 的程序了</p>
<pre><code class="language-cpp">// main.cpp
import std;

int main() {
    std::println("{}", 42);
}
</code></pre>
<p dir="auto">编译:</p>
<pre><code class="language-bash">g++ -std=c++23 -fmodules --compile-std-module main.cpp -o app
./app
</code></pre>
<h2>3. 诊断增强: 错误信息结构化 + 编译期静态代码分析</h2>
<p dir="auto">C++ 报错经常被吐槽，不是因为编译器不知道哪里错了，而是因为错误链太长，人很难从一堆候选函数、模板实例化和类型展开里看出主线。</p>
<p dir="auto">GCC 16 的一个明显变化是，部分 C++ 错误信息开始用层级结构展示。例如这个声明和定义不一致的例子:</p>
<pre><code class="language-cpp">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;
}
</code></pre>
<p dir="auto">编译:</p>
<pre><code class="language-bash">g++ diagnostics-mismatch.cpp
</code></pre>
<p dir="auto">GCC 16 会把候选函数和参数差异分层展示，核心信息大致是:</p>
<pre><code class="language-text">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*'
</code></pre>
<p dir="auto">这比以前只告诉你 找不到匹配声明 更有用，它一定程度指出了候选是谁、哪里不一致、哪一个参数出了问题。</p>
<p dir="auto">甚至还能生成更适合浏览器查看的诊断html页面:</p>
<pre><code class="language-bash">g++ diagnostics-mismatch.cpp \
  -fdiagnostics-add-output=experimental-html
</code></pre>
<p dir="auto"><img src="/assets/uploads/files/1777910315147-2026-05-04_22-55.png" alt="2026-05-04_22-55.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">如果想给 CI、IDE 或代码扫描平台使用，可以生成 SARIF:</p>
<pre><code class="language-bash">g++ diagnostics-mismatch.cpp \
  -fdiagnostics-format=sarif 
</code></pre>
<p dir="auto">这个的优化, 不仅 报错更容易看了，而且后面可能会影响工具链体验。编译器不再只是把错误打印到终端，而是可以把结构化诊断交给网页、编辑器、代码审查和静态分析系统。</p>
<p dir="auto">配合上 <code>-fanalyzer</code> 的能力。它是 GCC 自带的静态分析能力。如果加上 <code>-Werror</code> 体验就有点类似Rust的严格编译期检查功能</p>
<p dir="auto">看一个 use-after-delete:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;

int main() {
    int *p = new int(42);
    delete p;
    std::cout &lt;&lt; *p &lt;&lt; "\n";
}
</code></pre>
<p dir="auto">编译:</p>
<pre><code class="language-bash">g++ -std=c++20 -fanalyzer analyzer-uaf.cpp
</code></pre>
<p dir="auto">GCC 16 会给出类似警告:</p>
<pre><code class="language-text">warning: use after 'delete' of 'p' [CWE-416] [-Wanalyzer-use-after-free]
</code></pre>
<p dir="auto"><img src="/assets/uploads/files/1777910360646-6ac11e44-be1d-4668-bd20-b4243eb62f81-image.png" alt="6ac11e44-be1d-4668-bd20-b4243eb62f81-image.png" class=" img-fluid img-markdown" /></p>
<h2>4. C++26 特性: Reflection / 反射</h2>
<p dir="auto">GCC 16 实现了若干 C++26 特性，这里简单试一试</p>
<pre><code class="language-bash">-std=c++26 -freflection
</code></pre>
<p dir="auto">以一个简单的结构体为例, 看看 C++26反射 的功能:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;meta&gt;
#include &lt;string_view&gt;

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 &lt;&lt; type_name &lt;&lt; " has " &lt;&lt; field_count() &lt;&lt; " fields\n";
    std::cout &lt;&lt; field_name(0) &lt;&lt; ": " &lt;&lt; field_type(0) &lt;&lt; '\n';
    std::cout &lt;&lt; field_name(1) &lt;&lt; ": " &lt;&lt; field_type(1) &lt;&lt; '\n';
}
</code></pre>
<p dir="auto">编译运行:</p>
<pre><code class="language-bash">g++ -std=c++26 -freflection reflection-user.cpp -o reflection-user
./reflection-user
</code></pre>
<p dir="auto">输出:</p>
<pre><code class="language-text">User has 2 fields
id: int
score: double
</code></pre>
<p dir="auto">这里的 <code>^^User</code> 是对 <code>User</code> 这个结构体类型做静态反射，<code>std::meta::display_string_of</code> 可以拿到类型的显示名。<code>std::meta::nonstatic_data_members_of</code> 则能拿到结构体的非静态数据成员列表，再通过 <code>identifier_of</code> 和 <code>type_of</code> 分别取得成员名和成员类型。</p>
<p dir="auto">C++ 代码可以在编译期拿到结构体自身的字段信息。这个功能对 序列化、ORM、RPC、命令行参数解析、UI 绑定、测试生成等大量现在依赖宏、模板技巧或外部代码生成的场景 有重要影响</p>
<h2>5. 总结</h2>
<p dir="auto">GCC 16.1.0 感觉最核心的就是默认标准从C++17变成了C++20, 某种意义上也算正式迈入C++2x时代了, 下面是一些个人感觉</p>
<ul>
<li>1.默认 C++ 标准从 GNU++17 变成 GNU++20。能进一步加速C++生态进入C++2x的时代</li>
<li>2.C++20 modules特性 在 GCC 16 里只是做了部分优化, 相比GCC 15.1.0引入import std来说, 没有特别惊喜</li>
<li>3.诊断输出更结构化了。嵌套错误、HTML、SARIF 会让编译器错误更适合教学、CI 和 IDE 集成。</li>
<li>4.C++26 Reflection 已经可以初步尝试。对于个人项目可以上手用一用 (但可能存在很多潜在的坑)</li>
</ul>
<p dir="auto">我个人是比较关注模块化的进展, 总体来说GCC16虽然模块化特性上没有过多惊喜, 但在<code>import std</code>之后, 模块化算是已经初步可以在项目里尝试的水平了, 并且我们 mcpp-community 现代C++爱好者社区 已经在 模块化的 项目/库的 工程化、包管理、工具链 等方面有一定的探索, 欢迎感兴趣的朋友加入讨论</p>
<ul>
<li>社区Github主页: <a href="https://github.com/mcpp-community" rel="nofollow ugc">https://github.com/mcpp-community</a></li>
<li>C++23模块化项目: <a href="https://github.com/openxlings/xlings" rel="nofollow ugc">https://github.com/openxlings/xlings</a></li>
<li>C++23模块化库: <a href="https://github.com/mcpplibs" rel="nofollow ugc">https://github.com/mcpplibs</a></li>
</ul>
<h2>相关链接</h2>
<ul>
<li>xlings: <a href="https://github.com/openxlings/xlings" rel="nofollow ugc">https://github.com/openxlings/xlings</a></li>
<li>mcpp-community: <a href="https://github.com/mcpp-community" rel="nofollow ugc">https://github.com/mcpp-community</a></li>
<li>GCC 16.1 Released: <a href="https://gcc.gnu.org/pipermail/gcc-announce/2026/000190.html" rel="nofollow ugc">https://gcc.gnu.org/pipermail/gcc-announce/2026/000190.html</a></li>
<li>GCC 16 Release Series: Changes, New Features, and Fixes: <a href="https://gcc.gnu.org/gcc-16/changes.html" rel="nofollow ugc">https://gcc.gnu.org/gcc-16/changes.html</a></li>
<li>GCC 16.1.0: <a href="https://sourceware.org/pub/gcc/releases/gcc-16.1.0/" rel="nofollow ugc">https://sourceware.org/pub/gcc/releases/gcc-16.1.0/</a></li>
</ul>
]]></description><link>http://forum.d2learn.org/topic/203/gcc-16-上手初体验-环境配置-默认-c-20-模块化-诊断增强和-c-26-反射</link><guid isPermaLink="true">http://forum.d2learn.org/topic/203/gcc-16-上手初体验-环境配置-默认-c-20-模块化-诊断增强和-c-26-反射</guid><dc:creator><![CDATA[SPeak]]></dc:creator><pubDate>Invalid Date</pubDate></item></channel></rss>