差异
移除
数据类型
- 2的补码以外的有符号整数
语言特性
K&R风格函数声明与定义
比如 int main()
,是经常被使用的旧式写法。
或者
int add1(value)
int value;
{
return value + 1;
}
- 不再允许
u
/U
前缀的字符串字面量/字符常量为非UTF-16/32字符 __alignof_is_defined
和__alignas_is_defined
标准库
- 混合使用宽字符的连接
- 对
realloc()
传递0大小的调用(实现定义改为未定义) static_assert
宏(改为关键字)thread_local
宏(改为关键字)
废弃
标准库
<stdnoreturn.h>
,可使用[[noreturn]]标志
<math.h>
定义的数值界限INFINITY
,DEC_INFINITY
,NAN
,DEC_NAN
(移动到<limits.h
)asctime()
,可使用asctime_s()
ctime()
,可使用ctime_s()
- 特性测试宏:
__STDC_IEC_559__
,__STDC_IEC_559_COMPLEX__
,
可使用__STDC_IEC_60559_BFP__
和__STDC_IEC_559_COMPLEX__
。
DECIMAL_DIG
,序列化/反序列化long double
可能需要的十进制精度- __bool_true_false_are_defeined (现在true/false都成了关键字)
关键字
_Noreturn
函数限定符[[_Noreturn]]
属性
新增
语言特性
属性 (attribute)
[[fallthrough]]
表示从这里直落是有意的,编译器不应警告。
switch (cond) {
case A:
if ([expression]) {
doSomething();
[[fallthrough]];
}
case B:
case C:
printf("Error: ...");
[[fallthrough]];
case D:
doSomething();
break;
}
[[unsequenced]]
和[[reproducible]]
[[unsequenced]]
要求函数无状态,无副作用,幂等,并且独立。
其中:
- 无状态:没有定义可修改的静态或线程本地对象,也不调用有这种行为的函数。
- 无副作用:没有可观测的副作用。
- 幂等:重复的求值应当得到同样的结果。(可以读取全局状态)
- 独立:不依赖参数和常量以外的状态(可以写入全局变量)
[[reproducible]]
则只要求函数无副作用且幂等。
可通过("reason")
添加说明:[[deprecated("WTH are u using this")]]
告诉编译器不要因为未使用警告。
该类型/该函数的返回值不希望被直接丢弃。如错误信息,或者结果存储在返回值的函数。
可通过 ("reason")
添加说明:[[nodiscard("Error info should be processed")]]
。
该函数不通过return语句或达到底部返回。
应用于数组的限定修饰符
数组类型和它的成员的类型现在被认为总是被同样地限定
_Atomic
限定不可应用于数组。
const int A[1] = {};
int * ptr = A; // OK until C23
// clang: cannot initialize a variable of type 'int *' with an lvalue of type 'const int[1]'
// Note clang will apply this rule even in C89-C17
关键字
前三项可被编译器为兼容性定义为宏
static_assert
thread_local
true
,false
constexpr
存储周期修饰符/函数修饰符
预定义宏
- 不带message的
_Static_assert
宏(现在应使用static_assert
关键字) unreachable()
,表示代码不可达。
#include <stdint.h>
#include <stddef.h> // size_t and not has unreachable()
typedef struct color { uint8_t r, g, b, a; } color;
// color_vec that works over pointer-to-array
#define VEC_TYPE color
#define VEC_NAME color_vec
#include <vec.h>
void generate_texture(color** p_texture, size_t square_wh) {
switch (square_wh) {
case 128: [[fallthrough]];
case 256: [[fallthrough]];
case 512: /* ... */
color_vec_clear(p_texture);
color_vec_resize_init(p_texture,
square_wh * square_wh,
(color){0, 0, 0, 0});
break;
default:
unreachable();
}
}
数据类型
_Decimal32
,_Decimal64
以及 _Decimal128
。
- 位精度整数,
_BitInt(N)
- 二进制整数常量,以0b/0B前缀。
- nullptr常量和相关的nullptr_t类型
- char16_t 和 char32_t 字符串字面量 必须是 UTF-16 和 UTF-32
字面量
u8
前缀的 UTF-8 字符常量(u8'?'为单字节,u8"..." 为unsigned char [N]
)- 数字分隔符
'
,如 114'514'1919L
预处理器指令
#embed
const unsigned char icon_data[] = { // unsigned char为默认类型
#embed "art.png"
};
const char blob[] = {
#embed char "data.bin" // 其中char为类型名
};
const char qwq[] = {
#embed 32 "/dev/urandom" // 限制参数放在文件名之前;最多可以读入32字节。
// 注意这是上界,并不意味着一定会读入这么多。
};
该资源的内容以实现定义的方式映射到数据中,它为每个元素使用 CHAR_BIT * sizeof(type-name)
比特。如果该文件不足以多次填充这些位,则需要进行diagnostic。
其中类型名必须是基本整数类型。
#elifdef
#elifndef
#warning
其他
- 空初始化器
= {}
对于数组或自定义数据结构:对其成员空初始化;对于基本类型变量:对其本身空初始化。 - 函数定义中的不具名参数
- 声明或块结尾前的label
- 函数参数定义转发,可能在对ABI时需要使用。
标准库特性
现代的位运算工具
有端序的宏和一些常见的位运算工具。
printf()对整数的二进制格式化支持
使用“%b”描述符输出整数为二进制。
为格式化指定位长
当你想要输出一个很大的整数,之前的可移植做法是:
printf("%jd", (intmax_t)some_integer);
但是 int128_t , int256_t 得以支持后,我们也不能修改现存平台的 intmax_t
定义。于是:
printf("%w128d", my_128b_integer);
你也可以指定打印该数字的低位:
printf("%w8d", 0x114)
带溢出检查的整数运算
#include <stdckdint.h>
bool ckd_add(type1 *result, type2 a, type3 b);
bool ckd_sub(type1 *result, type2 a, type3 b);
bool ckd_mul(type1 *result, type2 a, type3 b);
这三个函数支持任意内建整数类型。