# GCC-13.2.0 编译安装
GCC 13.1 已被发布为 GCC 13 的第一个稳定版本,作为 GNU 编译器集合的年度功能发布。
GCC 13.1 是一个重大更新,为那些对一些老式编程感兴趣的人添加了 Modula-2 语言前端,虽然有新的 GCC Rust gccrs
代码,但它在 v13.1 中被禁用。在这个版本,GCC 的静态分析器继续改进,有更多的 C23 和 C++23 功能,并支持许多新的 x86_64/RISC-V/AArch64 处理器。
GCC 13.1 还提供了对 Ryzen 7000 系列和 EPYC 9004 系列处理器的初始 AMD Zen 4(Znver4)支持,OpenMP 卸载改进,支持以 JSON 为基础的 SARIF 格式发出诊断程序,Ada 2022 附加功能,各种新的 C/C++警告,支持 AMD 本能 MI200 系列用于 AMDGCN 后端,Ampere-1A 支持,Neoverse-V2/Cortex-X3/Cortex-X1C/Cortex-A715 支持,以及许多新的 Intel CPU 支持。GCC 13 增加了针对 Raptor Lake, Meteor Lake, Sierra Forest, Grand Ridge, Emerald Rapids 以及 Granite Rapids 的英特尔 CPU Target,以及相关的新英特尔 CPU 指令集扩展,如 AMX-FP16、AVX-IFMA、AVX-VNNI-INT8、AVX-NE-CONVERT、RAO-INT 和 AMX-Complex。
为了体验 C++20 的新功能,GCC 13.1 也是一个很好的选择,因为它包括对 C++20 的许多新功能的支持。截止到本文撰写时,GCC-13.2 也已发布,所以我直接选择了最新的版本。
# 下载 GCC-13.2.0 源码
下载与解压 GCC-13.2.0 源码
wget https://mirror.koddos.net/gcc/releases/gcc-13.2.0/gcc-13.2.0.tar.gz
tar -xzvf gcc-13.2.0.tar.gz
cd gcc-13.2.0
# 开始编译
- 编译命令:
./contrib/download_prerequisites
mkdir build && cd build
../configure --prefix=/root/software/gcc-13.2.0 \
--with-pkgversion='glibc gcc V13.2.0' \
--enable-checking=release \
--enable-languages=c,c++ \
--disable-multilib \
--enable-bootstrap \
--enable-threads=posix \
--with-system-zlib \
--with-gmp=$GMP_HOME \
--with-mpfr=$MPFR_HOME \
--with-mpc=$MPC_HOME \
make -j$(nproc)
make install
# 设置环境变量
# gcc-13.0.2.env
export GCC13_HOME=/root/software/gcc-13.2.0
export PATH=$GCC13_HOME/bin:$PATH
export LD_LIBRARY_PATH=$GCC13_HOME/lib64:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$GCC13_HOME/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$GCC13_HOME/libexec:$LD_LIBRARY_PATH
export CPATH=$GCC13_HOME/include:$CPATH
export INCLUDE=$GCC13_HOME/include:$CPATH
export CC=$GCC13_HOME/bin/gcc
export CXX=$GCC13_HOME/bin/g++
export FC=$GCC13_HOME/bin/gfortran
export F77=$GCC13_HOME/bin/gfortran
export F90=$GCC13_HOME/bin/gfortran
export F95=$GCC13_HOME/bin/gfortran
# 命令行测试
$ gcc -v
输出结果为:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/root/software/gcc-13.2.0/libexec/gcc/x86_64-pc-linux-gnu/13.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure --prefix=/root/software/gcc-13.2.0 --with-pkgversion='glibc gcc V13.2.0' --enable-checking=release --enable-languages=c,c++,fortran --enable-threads=posix --enable-bootstrap --disable-multilib --with-system-zlib --with-gmp=/root/software/gmp/6.2.1 --with-mpfr=/root/software/mpfr/4.1.0 --with-mpc=/root/software/mpc/1.2.1
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 13.2.0 (glibc gcc V13.2.0)
即为编译安装成功。
# C++ 20 主要新特性
- C++ 20 的主要新特性如下:
- Concepts(概念):概念是对模板参数的类型约束,它们使得模板代码更加清晰和易于理解。概念允许开发者定义一个接口,模板参数必须满足这个接口才能被接受。
- Ranges(范围库):这是对标准模板库(STL)的一个重大扩展,它引入了“范围”概念,以支持更加声明式的数据处理方式。
- Spaceship Operator(三路比较运算符):<=>被称为三路比较运算符,它可以一次性比较两个值,返回它们的相对顺序(小于、等于、大于)。
- Modules (模块):模块旨在替代传统的头文件和源文件分离方式,提供一种新的编译单元,可以显著改善编译时间和代码组织。
- Coroutines (协程):协程是一种轻量级的线程,它可以在不同的执行点之间切换,而不是在函数调用之间切换。协程是一种用于编写异步代码的新方法,它允许函数在不同的时间点暂停和恢复执行,而不需要回调函数或复杂的状态机。
- constexpr 改进:C++20 大大扩展了可以在编译时计算的代码的范围,包括允许
virtual
函数、try
和catch
块在constexpr
函数中使用。 - 初始化器列表的
std::to_array
:这允许将初始化器列表转换为 std::array ,从而提供了一种类型安全的方式来处理固定大小的数组。 - 模板语法的简化:typename 和 class 在模板参数中可以互换使用,简化了模板的语法。
- 新的标准属性:引入了多个新的属性,如
[[likely]]
和[[unlikely]]
,用于向编译器提供分支预测的提示。 - 新的标准库组件:例如
std::span
,它提供了一个视图,可以表示数组或其他连续序列的一部分,而不需要复制数据。 - 新的同步库:例如
std::latch
和std::barrier
,为多线程编程提供了新的同步原语。 - std::format:这是一个新的格式化库,它提供了一种类型安全的方式来格式化字符串。
- 其它等等
# C++ 23 主要新特性
- C++ 23 的主要新特性如下:
- Lambada
- 修复省略参数括号 () 的问题。
- 更改 lambda 尾部返回类型的作用域。
- 让支持函数的 attributes 都支持 lambda。这个功能其实很多编译器早已支持。
- 编译期计算:主要修复一些 bug 和继续完善编译期计算的能力。
- Deducing this : Deducing this 是 C++23 中最重要的特性之一。它其实就是提供一种将非静态成员函数的“隐式对象参数”变为“显式对象参数”的方法。
- Deducing this 的主要动机是消除成员函数修饰所带来的冗余。
- 多维数组:
- 支持多维下标运算符,即 operator[a, b, c, …]。
- 标准库引入 std::mdspan。
- 标准库:
- 增强 std::string 和 std::string_view
- 增强 std::optional
- std::flat_map 和 std::flat_set, 替代 std::map 和 std::set。
- std::stacktrace:用于 exception 捕获后,展开调用栈,方便调试。将 stacktrace 引入标准库,可以看作是对 C++ 异常处理能力的加强。
- std::excepted:对 C++ 通过返回值进行错误处理的能力加强。和 std::optional 差不多,但是 std::optional 只能表示正常值和空值(std::nullopt)。而 std::expected 则可以表示一个期望的值和一个错误的值,相当于两个成员的 std::variant,但是 std::excepted 的接口使用起来更方便。
- std::unreachable():给编译器的优化提示,告诉编译器这个地方是不可到达的。如果 std::unreachable() 被调用,其结果是 undefined behavior。
- 其它:
- 静态 operator() 和 静态 operator[]
- 假定表达式 [[assume(expr)]]
- size_t 字面量
- Lambada
# Corutines 协程示例
#include <coroutine>
#include <iostream>
#include <optional>
template<typename T>
struct Generator {
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct promise_type {
std::optional<T> current_value;
static auto get_return_object_on_allocation_failure() { return Generator{nullptr}; }
auto get_return_object() { return Generator{handle_type::from_promise(*this)}; }
auto initial_suspend() { return std::suspend_always{}; }
auto final_suspend() noexcept { return std::suspend_always{}; }
void unhandled_exception() { std::exit(1); }
template<typename U>
auto yield_value(U&& value) {
current_value = std::forward<U>(value);
return std::suspend_always{};
}
void return_void() {}
};
handle_type coro;
Generator(handle_type h): coro(h) {}
Generator(Generator const&) = delete;
Generator(Generator&& o) : coro(o.coro) { o.coro = nullptr; }
~Generator() { if (coro) coro.destroy(); }
T next() {
if (coro) {
coro.resume();
if (coro.done()) {
coro.promise().current_value.reset();
}
return *coro.promise().current_value;
}
return T{};
}
};
Generator<int> generateNumbers(int start, int end) {
for (int i = start; i <= end; ++i) {
co_yield i;
}
}
int main() {
auto numbers = generateNumbers(1, 5);
for (int i = 1; i <= 5; ++i) {
std::cout << numbers.next() << std::endl;
}
return 0;
}
编译命令:
g++ -o coroutines coroutines.cpp -std=c++20 -fcoroutines -O3
运行结果:
./coroutines
1
2
3
4
5
# Deducing this 示例
#include <iostream>
struct Test {
template <typename Self>
void explicitCall(this Self&& self, const std::string& text) {
std::cout << text << ": ";
std::forward<Self>(self).implicitCall();
std::cout << '\n';
}
void implicitCall() & {
std::cout << "non const lvalue";
}
void implicitCall() const& {
std::cout << "const lvalue";
}
void implicitCall() && {
std::cout << "non const rvalue";
}
void implicitCall() const&& {
std::cout << "const rvalue";
}
};
int main() {
std::cout << '\n';
Test test;
const Test constTest;
test.explicitCall("test");
constTest.explicitCall("constTest");
std::move(test).explicitCall("std::move(test)");
std::move(constTest).explicitCall("std::move(consTest)");
std::cout << '\n';
}