C23 杂记
Source: Dev.to
介绍
我已经在C23中针对各个新特性写了几篇文章,涵盖了属性、auto(链接)、bool(链接)、用于复合字面量的存储类、constexpr(链接)、枚举的显式底层类型enumerations、nullptr(链接)以及typeof(链接)。还有一些零散的新特性不足以单独成文,因此本文将把它们一起讨论。
聚合初始化
您现在可以使用空的 = { } 来初始化聚合(数组、结构体和联合)。以前必须在大括号之间至少包含一个 0。
二进制字面量
自 C 诞生以来,C 已经拥有十进制、八进制和十六进制整数字面量。C23 从 C++14 采用了二进制字面量,使用 0b 或 0B 前缀:
int n = 0b101010; // 42 decimal
_BitInt
新增了一种 位精确整数 类型,记作 _BitInt(n),其中 n 是正的常量整数表达式。它可以是有符号(默认)或 unsigned。 (如果是有符号,则 n 包含符号位。)一些示例:
unsigned _BitInt(24) rgb24; // 24‑bit RGB 颜色
unsigned _BitInt(256) sha256; // SHA‑256
n 的最大取值由实现决定,但至少与 unsigned long long 的位数一样多。
十进制浮点类型
虽然它们作为扩展已经存在一段时间,但新的十进制浮点类型 _Decimal32、_Decimal64 和 _Decimal128 现在已正式受支持。
十进制浮点类型更适合涉及金钱(美元、欧元、英镑等)的计算,因为它们不受标准浮点类型的舍入误差影响。标准浮点类型仍然是一般浮点计算的首选。
标签后的声明
现在可以在 goto 或 case 标签后立即放置声明:
error: // C < C23: error; C23: OK
int code;
以前,你必须使用一种技巧,例如在冒号后加一个空语句 (:;) 才合法。C 委员会本应在 C99 允许声明与代码交错时就把这项改为合法,但迟做总比不做好。
数字分隔符
C23 也从 C++14 中采用了 ' 字符作为数字分隔符,以提升可读性:
int n = 0b0010'1010;
int c = 299'792'458;
整体数值保持不变;你可以随意对数字进行分组。不能使用逗号,因为逗号已经用于分隔函数参数并充当 逗号运算符。
K&R‑风格函数
尽管函数原型在 C89(首个 ANSI C)时已从 C++ 中引入,C 仍然支持 “K&R 风格” 的函数声明和定义:
char* strncpy(); // C < C23: unspecified arguments
char* strncpy( dst, src, n )
char *dst;
char const *src;
size_t n;
{
/* ... */
}
C23 已经不再支持此类声明和定义。
New Keyword Spellings
除了 bool 替代 _Bool,alignas 替代 _Alignas,alignof 替代 _Alignof,static_assert 替代 _Static_assert,以及 thread_local 替代 _Thread_local,旧的拼写仍然受支持,但已被弃用。
新的预处理指令
预处理器现在包括 #elifdef、#elifndef、#embed 和 #warning 指令。
未命名的未使用参数
在历史上,C 语言要求未使用的参数必须命名,常用的消除“未使用”警告的方法是将参数强制转换为 void:
char** cdecl_rl_completion( char const *text,
int start, int end ) {
(void)end; // unused
/* ... */
}
在 C23 中,你可以直接省略参数名,就像在函数声明中一样。
__VA_OPT__
虽然它已经被 GCC 和 Clang 作为扩展支持了一段时间,但 __VA_OPT__ 现在已经成为 C 标准的一部分。
可变参数函数
正如前文所述,可变参数函数不再需要至少一个必需参数;你可以这样写:
void f( ... ) { // C23: no required parameter
va_list args;
va_start( args ); // C23: no second argument
/* ... */
}
此特性来源于 C++。
结论
在 C23 的所有改动中,auto 可能是使用最广的;但其他改动虽然不具革命性,却也很不错(有时甚至早该出现了)。