欢迎光临散文网 会员登陆 & 注册

Hello World 能有什么难度?C++20 # C++ 23

2023-03-02 23:28 作者:紧果呗  | 我要投稿

各位看官,实不相瞒,以在下十几年混迹于 PL 行业的底层,写得一手好 Hello world,风格各异,不下几十种姿势。今天就来表演一下 C/C++/C++20 的 Hello world。内容按以下三个主题组织:

# =🚩 Hello World from C to C++23

## ==⚡ GCC Clang & C++20 

## ==⚡ MSVC & C++20

代码及配置相关文件可以前往此处获取 [Tour of C++ 2023](https://github.com/Jeangowhy/Tour-of-C-2023)


为了跟得上三大流编译器的足迹,需要提前安装好相应开发环境,本机当前配置:

Windows: Visual Studio 2019 / 2022 社区版,LLVM Clang 14,MinGW-w64  GCC 12.2

Windows WSL:Homebrew 环境下安装 GCC 12.2 和 Clang 15

- http://www.cplusplus.com/reference/cstdio/

- http://www.cplusplus.com/reference/iostream/cout/

- [MSYS2](https://www.msys2.org/docs/what-is-msys2/)

- [Pacman Wiki](https://wiki.archlinux.org/title/Pacman)

- [Pacman Base Packages](https://packages.msys2.org/base)

- [Installing GCC](https://gcc.gnu.org/install/index.html)

- [MinGW-w64](https://www.mingw-w64.org/downloads/)

- [LLVM Project](https://github.com/llvm/llvm-project/releases)

PS: Godot 4.o 发布了,为了这 Hello World from C to C++23,我下载好的 Godot 4 RC5/6 都没时间打开来看。有个消息就是,Godot 4 临门一脚,把 Mono 换【踢】了,用了 .Net 6.0 ,只支持桌面 C# 开发,好处就是可以使用 C# 10.0。下载请这边来 https://godotengine.org/download/windows/ 

配置 Godot C++/C# VScode 开发环境,请这边来 Godot C++/C# VScode Settings


Hello World! for C


Hello World! for C++


Hello World! for C++20

模块化是 C++20 最重要的两个特性之一,另一个是协程 (Coroutine)。模块化引入可以解决从 C 语言中继承下来的 include 机制存在的问题:

- 模糊的模块边界;

- 循环处理导致编译效率低下;

- 宏展开会导致符号污染,也就是命令空间污染问题;


从 C 开始,标准库头文件就使用 .h 文件,但是在 C++ 引入 Standard Library 并不需要指定扩展名。比如 <iostream> 以及其它标准库,都定义在 std namespace 或者子命名空间内。

但是,C++ 依然为 C 标准库保留了两种形式,首先,是推荐使用的无扩展名的版本,如 <cstdio>,所有这些标准库都定义在 std 命名空间中。其次,是旧版本,像 C 语言中一样使用 .h 后缀扩展名,它们没有定义命名空间


比如,引入 <stdio.h> 这个标准库,它就是不使用 namespaces 特性的库。


需要注意的是,C++20 的模块方式下,所有 C 标准库不保证可以通过 import 导入,为了安全起见,应该使用 include 导入指令,而不是 import 导入。


要编译使用了 modules 特性的 C++ Hello World 是相当有门槛的,至少在目前阶段来说,大部分编译器没都没支持到模块化,即使用是最新的编译器,对 C++ 模块化支持也是部分功能的支持。


GCC 12.2 和 Clang 13.0.0 都不支持 std::format 模块功能。或者更确切地说,他们的标准库实现不支持它。Clang 14.0.0 的 libc++ 或者 GCC 13 libstdc++ 支持,但仍标记为不完整的功能。目前标准库还未曾实现模块化,也就不能使用 import 导入标准库,否则报错:

    cannot be imported because it is not known to be a header unit

Standard Library Header Units 即标准库的标头单元,标头单元是头文件和 C++ 20 模块中间步骤。


标头单元和头文件之间的一个重要区别是,标头单元不受标头单元之外的宏定义的影响。 也就是说,不能定义导致标头单元行为不同的预处理器符号,避免宏定义产生符号污染。导入标头单元时,就已经编译了标头单元。这与处理文件的方式 #include 不同。 包含的文件可能会受到头文件外部的宏定义的影响,因为在编译包含它的源文件时,头文件会经过预处理器。


必须将头文件转换为标头单元,才能导入该头文件。GCC 使用 -x c++-system-header 参数生成标头单元,生成文件在 gcm.cache 目录下。模块引入要严格遵守 modules 之间的依赖关系,被依赖的一定要放在前面。


但是,只要编译器还不支持 std::format(),就可以使用免费提供的 {fmt} 库作为替换。下载 {fmt} 库文件,将其中的 include/fmt 和 src 目录复制为项目中的 fmt 和 src 子目录。然后,根据需要引入 `fmt/core.h`, `fmt/format.h`, `fmt/format-inl.h`, `src/format.cc` 等等文件。

- https://fmt.dev/ 

- https://github.com/fmtlib/fmt

- [C++ iostream 的用途与局限](https://www.cnblogs.com/Solstice/archive/2011/07/17/2108715.html)

> C++ iostream 的主要作用是让初学者有一个方便的命令行输入输出试验环境,在真实的项目中很少用到  iostream,因此不必把精力花在深究 iostream 的格式化与 manipulator。iostream 的设计初衷是提供一个可扩展的类型安全的 IO 机制,但是后来莫名其妙地加入了 locale 和 facet 等累赘。其整个设计复杂不堪,多重+虚拟继承的结构也很巴洛克,性能方面几无亮点。iostream 在实际项目中的用处非常有限,为此投入过多学习精力实在不值。

C 语言的 stdio 库函数安全性问题比较严重,C99 增加了 snprintf() 等能够指定输出缓冲区大小的函数,输出方面的安全性问题已经得到解决;输入方面似乎没有太大进展,还要靠程序员自己动手。另外,扩展性不够,因为直接使用 FILE* 输入输出数据流,用户数据类型需要额外的处理。


C++ 设计 iostream 的初衷包括克服 C stdio 的缺点,提供一个高效的可扩展的类型安全的 I/O 机制。“可扩展”有两层意思,一是可以扩展到用户自定义类型,而是通过继承 iostream 来定义自己的 stream,“类型可扩展”和“类型安全”都是通过函数重载来实现的,也解决了旧有的安全性(security)方面的问题。


但是,C++ 添加了太多额外的功能,总想着考虑周全,这使得它变得非常沉重。其中一就是本地化功能,The Standard C++ Locale by Nathan C. Myers,所以在需要 I/O 性能优化的应用中慎用。


参考第三 key-value db:

- [Google leveldb](http://code.google.com/p/leveldb)

- [Kyoto Cabinet](http://fallabs.com/kyotocabinet/)

## ==⚡ GCC Clang & C++20

C++ 作为向后兼容 C 语言的一种系统底层高级编程语言,它的编译流程也基本和 C 语言的编译流程一致。C 语言在贝尔实验室刚诞生时,由于当时的计算机资源相当有限,其内存无法完全表示大型源文件的语法树。所以,为了能够编译大型项目,Dennis Ritchie 采用了分开编译源文件,最后链接形成可执行文件的编译单元化思想,让大文件的编译成为可能。


早期的 C 语言编译器也并不像现代的编译器做一个单独的可执行程序,Dennis Ritchie 为 PDP-11 编写的 C 语言编译器由七个可执行文件组成:cc/cpp/as/ld/c0/c1/c2。编译的步骤为:


01. 预编译:cpp 预处理器首先处理 #define,#Include 等指令,以及展开宏定义;

02. 编译:cc c0 c1 c2 编译器将源代码转化汇编代码;

03. 汇编:as 汇编程序将汇编代码转化为目标文件,并生成符号表,包括无定义的符号;

04. 链接:ld 连接器将多个源文件链接成可执行文件,处理上一步留下的无定义符号链接问题;


现在的编译器也很多是由单独功能的程序模块组成的编译工具链,如 GCC 编译器编译 C++ 程序分步骤流程:


- 预处理: gcc -E

- 编译: gcc -S

- 汇编: gcc -c 

- 链接: gcc -o 指定输出


预处理程序 preprocessor 是 C++ 编程中相当重要的一个阶段,它相当于是一个代码生成器,通过宏定义的展开,可以实现复杂的程序结构。C++20 从头文件引用转换到模块引用,其中一个问题就是头文件的预处理。

当下,Clang 作为一个优秀的编译器前端与 LLVM 编译器架构一起发扬光大,无论是对 C/C++ 规范的支持,编译速度,还是错误信息的友好度都是业界领先。无论是在工程,还是平时使用,Clang 都是一个可以作为第一选择的编译器。

关于 LLVM 编译器构架的介绍,参考Compilers Architecture 编译器构架

C/C++ Support in Clang

C++20 是有史以来最大的 C++ 版本更新,但是不知什么原因它又没有完全完工,是疫情版完成了后续的工作,C++23 “Pandemic Edition” is complete。要使用最新的功能,需要 GCC 11 或 CLang 12 版本。GCC 10.9 开始基础运行库命名为 libc++,早期的版本则默认为 libstdc,可以按需要安装指定版本。


虽然 C++20 开始引入模块化概念,但目前来说仍然不成熟,它需要解决的问题包含:


01. **Rewrite the world’s code**: 不向后兼容(历史包袱)扔掉头文件就需要重写整个工业基础库。

02. **Versioning**: 模块没有版本概念,开发者必须依赖语言底层的版本控制机制。

03. **Namespaces**: 与某些语言不同,模块并不暗示任何命名空间的概念,不同模块存在同名冲突。

04. **Binary distribution of modules**: 头文件,特别是 C++ 的头文件暴露了语言的全部复杂性。在体系结构、编译器版本和供应商之间,在技术上保持稳定的二进制模块格式不可行。


C++20 Modules 编译器支持度:


或者使用 VS 2022,当然,VS 2019(MSVC 16.8)已经开始支持模块,安装“用于 v142 生成工具的 C++ 模块(实验性)”,即可以获得模块化的标准库。


标头单元是头文件的二进制表示形式,各家编译器使用不同扩展名。标头单元文件是预编译内容的缓存文件,相当于编译出来的 object,链接的时候直接可用,比起头文件的嵌套处理快速多了。

[P1838R0: Modules User-Facing Lexicon and File Extension](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1838r0.pdf)


暂且将有点软的格式词库 Industry Foundation Class(IFC),其格式规范旨在定义一种用于在高抽象级别上描述 C++ 程序或程序片段语义的二进制格式,然后降为机器代码或类似代码。


格式化工具库的支持目前只有 MSVC 16.10 完全支持,Clang 14 使用 -stdlib=libc++ 支持,相对落后一点的 GCC 12.2 还不支持:


- [Text formatting in C++ using libc++](https://blog.llvm.org/posts/2022-08-14-libc++-format/)

- https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2020

- https://libcxx.llvm.org/Status/Cxx20.html

- https://github.com/fmtlib/fmt


而标准库模块化方面,GCC 和 Clang 都没有提供,VS 2019 16.10 版本以上则可以支持。Clang 15 支持规范标准:

以下使用 Homebrew 安装的 clang version 15.0.7,以及 GCC 12.2.0。

Clang 模块的一些定义规则:


- 模块文件使用 .cppm 扩展名,不像 GCC 可以使用支持的多个扩展名;

- 模块代码中以 `module;` 打头,但是 `export module` 语句要在 include 指令后面;

- 使用 --precompile 指令预编译模块时,输出名称要和源文件名一致;


模块定义以及测试参考如下,使用 Clang 编译时,一定要保存为 .cppm 文件。如果使用 GCC 编译,则宽松很多,保存为 .cc 或 .cxx .cpp 都是可以的,并且也不要求导出模块名称与文件名一致。不过,为了一致,还是保持一致的模块名与文件名为好。


Clang 参考编译命令:

因为当前 GCC 或 Clang 还未提供标准库模块化支持,导入标准库时,就需要手动编译标头单元文件。与用户定义的命名模块类似,使用 --precompile 编译标头单元文件生成 BMI,但是还需要额外指令,以下任选一种:


- 通过 -xc++-system-header-xc++-user-header 指定输入文件是头文件。

- 通过 -fmodule-header={user,system} 选项为 .h 或 .hh 文件生成 BMI。


默认值为 -fmodule-header=user,即相当于 MSVC 中使用 /headerUnit:quote 类似,按用户搜索路径定位标头文件。可以多次使用 -fmodule-file 以指定多个 BMI 文件。


GCC 在文件扩展名上的设计选择是,不支持新的拓展名,只支持原有的 .cc, .cxx, .cpp 等等拓展名。目前 GCC 12.2 还没有提供 <format> 标准库,使用 {fmt} 库替代。

GCC 编译命令参考,使用 PowerShell:

Windows 系统上,可以安装最新版本 MinGW-w64 编译工具以使用 GCC 12.2。Windows WSL 系统下可以使用 Homebrew 管理工具安装最新的 GCC 12。

但是,这个版本的 Link Time Optimization (LTO) 插件依赖更新的 GLIBC 2.33,没有更新到位就会导致链接失败。libLTO 插件作为 LLVM 的一部分,也是模块间优化 intermodular optimization, 一种用于代码链接阶段的优化技术。是优化代码的一系列编译器优化技术的集合,不同于其他的优化技术,LTO 聚焦于分析整个程序代码。

    ~/homebrew/Cellar/gcc/12.2.0/libexec/gcc/x86_64-pc-linux-gnu/12/liblto_plugin.so: 

    error loading plugin: 

        /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found

        (required by liblto_plugin.so)

WSL 软件仓库没有提供最新版,只好从源代码构建,根据网络速度选择下载 gz 或更大压缩率的 xz:

Linux 系统安装软件的基本流程是:configure → make → make install。配置文件是一个可执行脚本,其中 -–prefix 选项是配置安装的路径,如果不配置该选项,默认安装行为如下:

- 可执行文件放在 /usr/local/bin

- 库文件放在 /usr/local/lib

- 配置文件默认放在 /usr/local/etc

- 其它的资源文件放在 /usr/local/share


通过指定配置 -–prefix,可以把所有资源文件放在指定路径下,统一管理,此选项方便卸载软件或移植软件。

- [LLVM Link Time Optimization: Design and Implementation](https://www.llvm.org/docs/LinkTimeOptimization.html)

- [The GNU C Library (glibc)](https://www.gnu.org/software/libc/)

std::format 格式化参考:

扩展格式化接口,实现自定义类型格式化输出:

LLVM 子项目 libc++ 目前只支持类 Linux 平台,Windows 平台上只能借用 MSVC 或者 MingGW 提供的 C++ 运行库。官方文档表示 Clang 不是 MSVC 的替代品,而是补充。

通过 -fuse-ld=<linker name> 可以指定以下任何一种支持的链接程序:


01. GNU ld

02. GNU gold

03. LLVM’s lld

04. MSVC’s link.exe

Link-time optimization 原生支持持链接期优化,使用 gold 时通过链接程序插件支持。


Clang 支持以下两种 C++ standard library 实现,使用 -stdlib 参数的设置:

01. LLVM’s libc++,此库旨在成为从 C++11 开始的 C++ 标准完整实现,-stdlib=libc++

02. GCC’s libstdc++,Clang 支持 libstdc++4.8.3 及更高版本,-stdlib=libstdc++


另外,Clang 版本需要和 Visual Sutio 版本匹配,版本不匹配会出现编译或链接问题。Visual Studio 2022 安装包本身也提供了 Clang 15 编译器。如果已经手动下载安装了 LLVM Clang 14 则可以搭配 VS 2019 使用,注意 x86 或者 x86_64 也对应,两者版本不匹配就会出现编译问题。

    STL1000, "Unexpected compiler version, expected Clang 15.0.0 or newer."

另外,-fprebuilt-module-path 目录设置为 . 可能引起无法打开当前目录的问题,需要指定绝对路径:

    LINK : fatal error LNK1104: 无法打开文件“.”

在 Windows 下使用 Powershell 执行编译命令时,可以会出现 clang 找不到基础运行库的问题。需要使用 Visual Studio 提供的运行时,使用 VC 环境脚本可以提供环境配置。需要注意,PowerShell 没有 @call 这个指令。使用 cmd /k 调用脚本后,不会保留环境配置信息。只能进入 cmd 环境下执行编译命令。


当然,可以使用 cmd /c 执行环境配置脚本后,将配置信息通过 SET 指令打印出来,再使用 PowerShell 进行二次处理,也可以实现一定的自动配置功能,但这已经失去了方便使用的的原则。


这就需要使用开发环境提供的一个专用模块 “Microsoft.VisualStudio.DevShell.dll”,用它来初始化 PowerShell VC 编译环境。可以安装 Windows Terminal 终端工具,方便运行编译环境。


命令行直接以新进程方式运行,如果要在 PowerShell 执行,就需要使用反引号对参数中的双引号进行转义。



以下是 Windows 系统,Visual Studio 2019 社区版,MinGW-w64 GCC 12.2 以及 LLVM Clang 14,等三大编译器的 Sublime 构建配置参考,MSVC 部分放在下一节内容:

Clang & GCC

## ==⚡ MSVC & C++20

通过 Sublime 构建工具调用 MSVC 编译 C++20 程序,配置参考如下:

MSVC C++20 Modules
MSVC C++23

Visual Studio 2019 默认没有支持 C++20,也未完全支持模块。编写和使用自己的模块通常效果很好,但导入标准库标头就不能做到开箱即用。VS 2019 16.8 版本才开始支持 P1103R3 Modules。


首先,需要修改项目配置,启用 C++20 规范或草案,使用右键菜单设置项目属性:

- C/C++ ➪ Language ➪ C++ Language Standard 

    - ISO C++20 Standard (/std:c++20) 

    - Preview - Features from the Latest C++ Working Draft (/std:c++latest)

为了实现标准库可以作为模块导入,需要做一点标头单元的处理工作,将需要引用的标准库统一放置在一个全局头文件中,比如 HeaderUnits.h,它包含所有标准库的导入:

Visual Studio 2019 项目的解决方案浏览器中,执行以下操作,通过右键设置 HeaderUnits.h 属性,在 Configuration Properties 面板中按以下步骤设置:

- General ➪ Item Type  ➪  C/C++ Compiler 设置好并应用设置;

- C/C++ ➪ Advanced ➪

    - Compile as C++ Header Unit (/exportHeader)

    - Compile as C++ Module Internal Partition (/internalPartition)

经过以上设置,MSBuild 工程文件中会有相应更新:

如果没出现相应的 C++ Header Unit 高级主编译选项,那么就需要更新到最新版本。标头单元编译功能需要 Visual Studio 2019 version 16.10 以上版本支持,MSVC 编译器版本号为 19.29。


然后,重新编译项目,/exportHeader (Create header units) 选项会让编译器生成标头单元文件。编译器会为标头单元生成相应的 IFC (.ifc) 文件,这里生成的是 HeaderUnits.h.ifc。


标头单元**header unit**是头文件的二进制表示,MSVC 使用 .ifc 扩展名表示标头单元文件,以及编译好的命名模块 (.ixx, .cppm, .h, .hpp)。


如果使用模块实现分区,也称为内部分区 Module Internal Partition,可以设置 /internalPartition。


编译生成成标头单元文件后,使用 /headerUnit 来引用它,将标头单元文件与头文件关联起来:

后缀 quote 和 angle 分别表示查找已编译的标头单元文件的两种规则,分别是按 `#include "file"` 和 `#include <file>` 一样的规则查找。没有后缀则在当前目录下,或者按指定的 ifc 文件路径查找。


MSVC 提供多个标头单元编译方法:


01. Build a shared header unit project,使用一个静态库工程引用需要使用的标头单元,

    这种方法可以更精细控制导入库的标头单元。

    https://learn.microsoft.com/en-us/cpp/build/walkthrough-import-stl-header-units?view=msvc-160

02. 将单个头文件编译为标头单元,即上面介绍的操作方法,适用于少量头文件的处理。

    https://learn.microsoft.com/en-us/cpp/build/walkthrough-header-units?view=msvc-160#approach1

03. Automatically scan for and build header units. 自动扫描头文件并编译标头单元,需要

    对项目源代码做描述。项目需要做如下配置:

    - All Configurations → C/C++ → General

    - → Scan Sources for Module Dependencies (YES)

    - → Translate Includes to Imports (/translateInclude)

    https://learn.microsoft.com/en-us/cpp/build/walkthrough-header-units?view=msvc-160#approach2

04. VS 2019 16.11 版本支持使用 /std:c++20 直接将 include 的头文件编译为标头单元而无需改动源代码。


标头单元配置文件 header-units.json 有两个目的:

- 在指定 /translateInclude 编译选项时用来确定那些头文件需要转译成标头单元。

- 最小化复制符号以提高编译命令生成的吞吐量。


为了查看 Visual Studio 编译过程的细节信息,可以打开选项设置为诊断输出模式:

- Tools ➪ Options... ➪ Projects and Solutions ➪ Build And Run ➪ 

    - MSBuild project build output verbosity ➪ Diagnostic


或者使用 msbuild 命令进行构建,:

    msbuild ..\msvc\demo.vcxproj -t:Rebuild -property:platform=x86

编译标头单元的 MSVC 命令行就如以下那样使用了非常复杂的、繁多的参数,但是构建一个标头单元配置文件需要使用 /sourceDependencies:directives 编译指令,此指令需要在标头单元文件 .ifc 文件生成之前使用。


然后,再使用一个名称类似的指令 /sourceDependencies,它会根据源代码级别依赖,将标准库头文件编译为标头单元,同时生成依赖信息文件,.ifc.d.json。


得到标头单元文件后,再使用 /headerUnit 指令将其与源头文件或标准库文件关联起来,最后与程序源代码编译生成可执行程序。



## ==⚡ C++2023 模块化参考资料


-  Bjarne Cxx HOPL4 paper - C++20:方向之争](https://github.com/Cpp-Club/Cxx_HOPL4_zh/blob/main/09.md)

- [P1103R3 Merging Modules](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1103r3.pdf)

- [探索c++底层编译原理](https://www.cnblogs.com/zhangshinan/p/12971792.html)

- [C/C++编译构建相关问题](https://www.cnblogs.com/hongyugao/p/15499494.html)

- [Support for C++20 Modules](https://www.jetbrains.com/help/clion/support-for-c-20-modules.html)

- [C++ 20 协程 concept ranges modules](https://www.bilibili.com/video/BV1kV411h78u/)

- [C++20 modules with GCC11](https://blog.feabhas.com/2021/08/c20-modules-with-gcc11/)

- [C++20 新特性: modules 及实现现状](https://zhuanlan.zhihu.com/p/350136757)

- [Invoking GCC - 3.23 C++ Modules](https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Modules.html)

- [C++ Support in Clang](https://clang.llvm.org/cxx_status.html)

- [Clang 17 - Modules](https://clang.llvm.org/docs/Modules.html)

- [Clang 17 - Standard C++ Modules](https://clang.llvm.org/docs/StandardCPlusPlusModules.html)

- [Clang CLI reference](https://clang.llvm.org/docs/ClangCommandLineReference.html)


01. https://learn.microsoft.com/en-us/cpp/build/walkthrough-header-units

02. https://learn.microsoft.com/en-us/cpp/cpp/tutorial-import-stl-named-module

03. https://learn.microsoft.com/en-us/cpp/cpp/tutorial-named-modules-cpp

04. https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros

05. https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance

06. https://learn.microsoft.com/en-us/visualstudio/releases/2019/release-notes

07. [/exportHeader](https://learn.microsoft.com/en-us/cpp/build/reference/module-exportheader)

08. [/headerUnit](https://learn.microsoft.com/en-us/cpp/build/reference/headerunit)

09. [/headerName](https://learn.microsoft.com/en-us/cpp/build/reference/headername)

10. [Overview of modules in C++](https://learn.microsoft.com/en-us/cpp/cpp/modules-cpp)

11. [Visual C++ 中生成和导入标头单元](https://learn.microsoft.com/zh-cn/cpp/build/walkthrough-header-units)

12. [Microsoft C++ Docs](https://github.com/MicrosoftDocs/cpp-docs/)

13. [WSL](https://github.com/Microsoft/WSL/)

14. [Windows Console](https://github.com/Microsoft/Terminal/)

15. [Hyper-V](https://github.com/MicrosoftDocs/Virtualization-Documentation)

16. [Windows Terminal](https://github.com/Microsoft/Terminal/)

17. https://github.com/sirredbeard/Awesome-WSL



Hello World 能有什么难度?C++20 # C++ 23的评论 (共 条)

分享到微博请遵守国家法律