虽然没有固定标准,但一般将C99之后的C语言标准称为“现代C语言”,目前的最新标准为C23。C语言的演化包括标准C89、C90、C99、C11、C17和C23,C23是C语言标准的一次重大修订,截至2024年3月,最新版本的gcc和
clang实现了C23的大部分新语言功能,但是部分功能仍然缺失,例如:constexpr
存储类说明符,[[unsequenced]]
和 [[reproducible]]
属性等等。
以下是比较重要的变化,完整变化列表可以参阅https://en.cppreference.com/w/c/23
或ISO标准文档。
1. 替代
<assert.h>
中的static_assert()
宏被替代,变成了static_assert
关键字;
<threads.h>
中的thread_local()
宏被替代,变成了thread_local
关键字;
<time.h>
中的ctime()
函数弃用,请使用ctime_s()
替代;
<time.h>
中的asctime()
函数弃用,请使用asctime_s()
替代;
<stdnoreturn.h>
与_Noreturn
标识符均弃用;
<stdalign.h>
中的alignas()
和alignof()
宏被弃用,请直接使用_Alignas
和_Alignof
关键字;
2. 新增
C23新增了三个十进制浮点数数据类型(关键字):_Decimal32
、_Decimal64
和_Decimal128
,对应的后缀是DF
、DD
和DL
。它们的最大值分别如下:
DEC32_MAX 9.999999E96DF
DEC64_MAX 9.999999999999999E384DD
DEC128_MAX 9.999999999999999999999999999999999E6144DL
C23可以使用二进制字面量了,使用0b或者0B开头,例如:
int num = 0b1011;
C23的字面量可以加分隔符了,增强可读性,例如:
int num2 = 100'020'050;
C23添加了bool
、true
、false
三个关键字,可以像C++一样定义布尔类型了:
bool choice = true;
C23新加了nullptr
关键字,它是nullptr_t
类型的,可以被强制转换为任意指针类型(传统空指针)及布尔类型(可用于逻辑判断):
void func(int a, nullptr_t b) {
//...
}
func(10, nullptr);
int *a = nullptr;
if(!a) {
printf("A is nullptr");
}
C23添加了双括号属性(Attributes)了,常用的比如:
[[deprecated]]
[[nodiscard]]
[[noreturn]]
[[maybe_unused]]
C23新加了一些预编译命令,常用的比如:
#elifdef
#elifndef
#warning:让编译器抛出警告
#embed:让编译器直接内嵌二进制数据
static const char song[] = {
#embed <music.wav> // 内嵌二进制文件数据
};
C23增加了空初始化列表支持,也就是说:
int a[5] = { 0 };
// 可以直接写成
int a[5] = {};
// 等价于
int a[5] = { 0, 0, 0, 0, 0 };
C23的宏支持__VA_OPT__
了,能更方便地解决使用宏时末尾符号的问题
C23给<stdio.h>
中的printf()
函数添加了%b
和%B
支持,能像打印16进制(%x %X)
一样直接打印二进制数据了;scanf()
也增加了%b
支持
C23给<string.h>
增加了memccpy()
,与memcpy()
类似但遇到某个特定值时会立刻停止复制
C23给<string.h>
增加了strdup()
与strndup()
,用于复制出一个新的(部分)字符串
C23引入了函数定义时的匿名参数,如果一个参数因为某种原因必须被传递但却不被使用,就可以把它设置为匿名参数:
int func(int num, char*)
{
return num + 5;
}
C23引入了constexpr
支持,可以定义编译期变量了
constexpr int c = 10/2;
C23将auto
关键字的语义进行了修改。auto
原本作为Storage class specifier
时极少使用,因此auto
在C23里变为了自动类型推导关键字。是的,C语言也可以使用auto
推导了:
const char* func()
{
return "Hello!";
}
auto ret = func();
C23增加了对“X位整数”的支持,类型关键字为_BitInt()
,编程时可以自由指定整数是几位。类型对应的字面量后缀是wb/WB
和uwb/UWB
例如:
// 12位无符号整数
unsigned _BitInt(12) a = 0uwb;
<uchar.h>
中加入类型char8_t
,存储UTF-8字符。类型对应的字面量前缀是u8
。例如:
char8_t srt[] = u8"你好!";
C23允许给enum
(枚举类型)指定类型了,如果不指定类型则默认为int
。例如:
enum flags: unsigned long {
err1 = 0xCOOOFFFF;
err2 = 0xC0010000;
}
C23引入了typeof支持:
int a = 10;
typeof(a) b = 5;
3. 删除
<stdlib.h>
中的realloc()
不再支持size
为0的情况,改为未定义行为;- C23取消了对三字母词(Trigraph)的支持。三字母词是一种转义字符,由
??
开头。例如在字面量中使用??)
代替]
。 - C23规定整数必须使用补码存储,不应再使用原码和反码;
- C23决定不再支持
K&R
格式。K&R
格式是一种老式C语言写法,例如:
// K&R
int func1(a, b, c)
int a;
char* b;
int c;
{
return a + c;
}
// 等价于现代语法
int func1(int a, char* b, int c)
{
return a + c;
}
Modern C :https://inria.hal.science/hal-02383654
C23 :http://cpp.7fa4.cn/zh/c/23.html