简介
2026年8月时,C语言最新的正式标准是 C23(ISO/IEC 9899:2024),是自C11/C17以来的一次重大更新,引入了众多旨在提升语言安全性、表达力与现代化程度的新特性。开始了解并逐步在项目中采用C23的新特性,将有助于编写更安全、更清晰、更高效的代码。

版本更新历史:
| 标准 | 年份 | 重点 |
|---|---|---|
| C89(C90) | 1989 | 基础 C 语言 |
| C99 | 1999 | stdint.h、bool、变长数组 VLA、_Generic、指定初始化器 |
| C11 | 2011 | 原子、多线程、静态断言_Static_assert、泛型_Generic |
| C17 | 2018 | 仅缺陷修复,无新语法 |
| C23 | 2024 | nullptr、auto、typeof、_BitInt、[[属性]]、ckd 溢出检查、memset_explicit、#embed |
C23 不会改变 C“简单、底层、无 GC” 的定位,主要解决历史坑,增加安全工具。
一、语言核心新特性(带示例)
1. nullptr 关键字,类型安全空指针
旧 C:NULL本质是0或者(void*)0,容易和整数混淆; C23:nullptr是关键字,类型nullptr_t,只能赋值给指针,不能隐式转 int。
#include <stddef.h>
#include <stdio.h>
int main(void)
{
int* p = nullptr;
if(p == nullptr){
printf("p is null pointer\n");
}
// int x = nullptr; //编译报错,不能赋值给整型
return 0;
}
2. auto局部变量类型推导(仅局部变量,不能函数参数 / 返回值)
⚠️ 和 C++ 不一样:C23 的
auto必须带初始化器,不能用于函数、数组参数、返回值。
#include <stdio.h>
int main(void)
{
auto a = 10; // int
auto b = 3.14; // double
const auto c = 99UL; // const unsigned long
// auto v; //错误,没有初始化器
printf("%d %.2f %lu\n", a, b, c);
return 0;
}
3. typeof() / typeof_unqual() 类型萃取
获取表达式的类型,宏、泛型编程非常好用。
typeof(expr):保留 cv 限定符 (const/volatile)typeof_unqual(expr):去掉 const/volatile 限定符
#include <stdio.h>
int main(void)
{
const int x = 100;
typeof(x) v1 = 200; // const int
typeof_unqual(x) v2 = 300; // int,可以修改
v2 = 400;
printf("%d %d\n", v1, v2);
return 0;
}
4. _BitInt(N) 精确位宽整数类型
不需要<stdint.h>,直接声明 N 位的有符号 / 无符号整数,嵌入式位操作神器,N 为编译期常量。
#include <stdio.h>
int main(void)
{
_BitInt(7) i7 = 0x3F; //7位有符号
unsigned _BitInt(12) u12 = 0xFFFU; //12位无符号
printf("_BitInt(7):%d\n", (int)i7);
printf("u12:%u\n", (unsigned)u12);
return 0;
}
5. 属性语法 [[attr]] 标准化(C23 正式纳入)
GCC/Clang 扩展属性标准化,取代__attribute__。
[[nodiscard]]:返回值必须被使用,否则警告[[maybe_unused]]:消除未使用变量警告[[unreachable]]:标记代码永远不会执行到,用于优化,UB 如果走到这里GitHub。
#include <stdio.h>
[[nodiscard]] int calc(int a, int b)
{
return a + b;
}
int main(void)
{
[[maybe_unused]] int temp = 10;
// calc(1,2); //警告:nodiscard返回值被丢弃
int x = calc(1,2);
printf("%d\n", x);
switch(x){
case 3: break;
default: [[unreachable]];
}
return 0;
}
6. 无参函数简化:void func();等价于void func(void);
C 旧标准:void f();代表任意参数; C23 修改规则:void f();等价于void f(void);,代表无参数,消除历史大坑。
void foo(); //C23:等价 void foo(void);
void foo(){
printf("no args\n");
}
int main(void){
foo();
// foo(123); //C23编译报错,不允许传参
return 0;
}
7. UTF‑8 字符字面量 u8'c'
之前只有u8"字符串",C23 支持 u8 单字符字面量。
char ch = u8'中';
8. #embed 预处理指令:源代码直接嵌入二进制文件
把外部文件的二进制字节嵌入编译后的程序,替代xxd工具生成头文件。
//把logo.bin全部字节嵌入数组
const unsigned char bin_data[] = {
#embed "logo.bin"
};
9. 十进制浮点数 _Decimal32 / _Decimal64 / _Decimal128
金融计算,十进制精确运算,规避二进制浮点数误差;后缀DF DD DL。注意:部分编译器是可选实现。
_Decimal64 money = 123.45DD;
10. 弃用的旧特性
- 弃用
<stdnoreturn.h>,直接用[[noreturn]]属性 - 弃用
<stdalign.h>宏,直接使用关键字_Alignas、_Alignof。
二、C23 新增标准库
1. 溢出检查整数运算 <stdckdint.h>
ckd_add、ckd_sub、ckd_mul:计算同时检测整数溢出。返回溢出布尔,结果输出到指针参数。
#include <stdio.h>
#include <stdckdint.h>
int main(void)
{
int res;
int overflow = ckd_add(&res, INT_MAX, 1);
if(overflow){
printf("integer overflow!\n");
}
return 0;
}
2. <string.h>新增函数
memset_explicit:安全擦除内存,编译器不能优化消除,用于清除密码、密钥等敏感内存;普通 memset 会被编译器优化删掉GitHub。
char password[] = "secret123";
memset_explicit(password, 0, sizeof password);
memccpy:拷贝内存,遇到指定字节或者拷贝满 n 字节就停止,POSIX 进标准。strdup、strndup正式纳入 C 标准(之前是 POSIX 扩展)。
3. IEEE‑754 浮点库增强
新增大量浮点函数:roundeven、fmaxmag,浮点环境编译期#pragma STDC FENV_ROUND设置舍入模式等isocpp.ope…。
4. 弃用库函数
asctime()被标记弃用,建议使用asctime_s()。
三、完整可编译 C23 综合 demo 单文件
编译命令:
gcc -std=c23 c23_demo.c -o c23_demo -Wall注意:stdckdint.hGCC14 + 才完整支持。
#include <stdio.h>
#include <stddef.h>
#include <limits.h>
#include <stdckdint.h>
#include <string.h>
[[nodiscard]]
int add(int a, int b)
{
return a + b;
}
int main(void)
{
printf("==== C23 Demo start ====\n");
//1. nullptr
int* p = nullptr;
if(p == nullptr){
printf("1. nullptr test ok\n");
}
//2. auto局部推导
auto va = 100;
auto vb = 2.718;
printf("2. auto: va=%d vb=%g\n", va, vb);
//3. typeof
const int cx = 999;
typeof_unqual(cx) vcx = cx;
vcx = 888;
printf("3. typeof_unqual: vcx=%d\n",vcx);
//4. _BitInt精确位宽
unsigned _BitInt(10) bit10 = 0x3FFU;
printf("4. _BitInt(10): %u\n", (unsigned)bit10);
//5. nodiscard属性
int sum = add(11,22);
printf("5. nodiscard add=%d\n", sum);
//6. ckd_add溢出检查
int out;
int ov = ckd_add(&out, INT_MAX, 1);
printf("6. ckd_add overflow=%d\n", ov);
//7. memset_explicit 擦除敏感内存
char secret[] = "my_passwd";
memset_explicit(secret, 0, sizeof secret);
printf("7. memset_explicit done\n");
printf("==== Demo end ====\n");
return 0;
}
其他
- C23 的
auto不是 C++auto,仅限局部变量,必须初始化; _BitInt、_DecimalXX属于可选特性,不是所有硬件平台编译器都实现;#embed二进制嵌入,部分编译器版本支持不全;void f();含义变更,老项目迁移注意。
C23 定位:增强安全性、现代化语法、补齐长期痛点、少量新类型、标准库扩充,没有颠覆性改动,向下兼容 C11/C17。