poly000客栈

C23特性简介

差异

移除

数据类型

  • 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> 定义的数值界限INFINITYDEC_INFINITYNANDEC_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

字面量

  • 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

其他

标准库特性

现代的位运算工具

stdbit.h

有端序的宏和一些常见的位运算工具。

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);

这三个函数支持任意内建整数类型。

参考资料

Copyright © 2024 poly000 Views