C语言标准 C23(ISO/IEC 9899:2024)示例

C/C++ wes 1 day ago (2026-08-10) 14 views
📑 本文导航

简介

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 &lt;stdio.h&gt;

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 &lt;stdio.h&gt;

[[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_addckd_subckd_mul:计算同时检测整数溢出。返回溢出布尔,结果输出到指针参数。

#include &lt;stdio.h&gt;
#include &lt;stdckdint.h&gt;

int main(void)
{
    int res;
    int overflow = ckd_add(&amp;res, INT_MAX, 1);
    if(overflow){
        printf("integer overflow!\n");
    }
    return 0;
}

2. <string.h>新增函数

  1. memset_explicit:安全擦除内存,编译器不能优化消除,用于清除密码、密钥等敏感内存;普通 memset 会被编译器优化删掉GitHub。
char password[] = "secret123";
memset_explicit(password, 0, sizeof password);
  1. memccpy:拷贝内存,遇到指定字节或者拷贝满 n 字节就停止,POSIX 进标准。
  2. strdupstrndup正式纳入 C 标准(之前是 POSIX 扩展)。

3. IEEE‑754 浮点库增强

新增大量浮点函数:roundevenfmaxmag,浮点环境编译期#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 &lt;stdio.h&gt;
#include &lt;stddef.h&gt;
#include &lt;limits.h&gt;
#include &lt;stdckdint.h&gt;
#include &lt;string.h&gt;

[[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(&amp;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;
}

其他

  1. C23 的auto不是 C++auto,仅限局部变量,必须初始化;
  2. _BitInt_DecimalXX属于可选特性,不是所有硬件平台编译器都实现;
  3. #embed二进制嵌入,部分编译器版本支持不全;
  4. void f();含义变更,老项目迁移注意。

C23 定位:增强安全性、现代化语法、补齐长期痛点、少量新类型、标准库扩充,没有颠覆性改动,向下兼容 C11/C17。