文章目录
- 概述
- C标准发展历程
- ANSI C标准
- C99标准
- C99新增关键字
- C99新增特性
- 语法与变量定义
- 预处理与编译内置
- 新增标准头文件与类型
- 标准库与格式化输出
- C11标准
- C11新增关键字
- C11新增特性
- 语法与类型扩展
- 并发、原子、多线程
- 标准库变更与安全优化
- 预处理与兼容性调整
- C23标准
- 相关参考
概述
C语言发展之初,并没有正式的标准。1978年,布莱恩•柯林汉和丹尼斯•里奇合著的C语言程序设计》第一版被公认为是C语言最早的标准,通常也被称为K&R C。随着C语言的不断发展,第一个C语言正式标准,即ANSI C,于1989年发布,这是目前使用最广泛的版本,也称C89。后续C标准继续修订并加入新的特性,陆续又发布了C99、C11等标准,最新的C标准已经到了C23。
C标准发展历程
C标准发展史编排如下:
| C标准 | 发布时间 | 描述 |
|---|
| ANSI C | 1989 | 由美国国家标准协会(ANSI)开发,定义了C语言和C标准库,也称C89 |
| ISO C | 1990 | 由国际标准化组织(ISO)发布,是与ANSI C完全相同的标准,也称C90 |
| C99 | 1999 | C标准委员会对C语言不断改进,并收纳为新的标准,于1999年正式发布,简称C99,也是严格意义上C语言的第二个正式版本 |
| C11 | 2011 | C标准委员继续对C语言进行改进,并收纳为新的标准,于2011年正式发布,简称C11 |
| C17/C18 | 2017 | C17/18主要是C11标准错误的修正,无新特性引入,于2017年发布 |
| C23 | 2023 | 现代化C语言,也是最新的C语言标准,简化语法,增强安全,同时删除了大量旧时的特性,于2023年发布 |
GCC编译器扩展
除了C语言官方发布的标准,例如GCC编译器也会提供额外的非标准语言特性支持,这些扩展特性被加入到了编译器的选项中,可以由用户指定编译选项进行使用。GCC编译器的C标准实现包括gnu89、gnu99、gnu11等,可以统称为GNU C标准,本质上就是对应版本的C语言标准特性+编译器扩展特性的合集。关于GNU C标准的扩展特性,可以通过查看GCC工具手册进行了解,编程人员可以通过制定-std=选项来选择特定的标准使用。
ANSI C标准
作为C语言的第一个正式标准,ANSI C定义了C语言的基础语言特性以及标准库相关的内容。ANSI C包含的语言特性如下:
- 关键字:ANSI C一共定义了32个关键字,包含数据类型、存储类别等,是C语言初代标准关键字集合。
- 语法基础:定义了分支、循环、跳转等基础语句语法,支持指针、数组、函数以及预处理等功能;
- C语言标准库
ANSI C标准关键字
| 关键字 | 描述 |
|---|
| auto | 声明自动局部变量,默认存储类别 |
| break | 跳出循环或switch分支 |
| case | switch语句分支匹配标签 |
| char | 字符基础数据类型 |
| const | 修饰只读常量,变量不可修改 |
| continue | 终止当前本轮循环,直接进入下一轮循环 |
| default | switch分支无匹配时执行的默认分支 |
| do | do-while循环起始标识 |
| double | 双精度浮点数据类型 |
| else | if条件不满足时执行的分支 |
| enum | 定义枚举自定义数据类型 |
| extern | 声明外部全局变量或外部函数 |
| float | 单精度浮点数据类型 |
| for | for循环语句关键字 |
| goto | 无条件跳转到代码自定义标签处 |
| if | 条件判断语句关键字 |
| int | 基础整型数据类型 |
| long | 长整型修饰符,扩大数值存储范围 |
| register | 建议编译器将变量存入CPU寄存器,提升读取速度 |
| return | 函数返回数据,终止当前函数运行 |
| short | 短整型修饰符,缩小整型占用字节 |
| signed | 有符号修饰符,变量可存储正负数值 |
| sizeof | 单目运算符,计算类型/变量占用内存字节数 |
| static | 静态修饰:局部变量生命周期延长;全局变量仅当前文件可见 |
| struct | 定义结构体复合数据类型 |
| switch | 多分支条件匹配语句 |
| typedef | 为已有数据类型自定义别名 |
| union | 定义共用体(联合体)数据类型 |
| unsigned | 无符号修饰符,变量仅存储非负数 |
| void | 空类型:无返回值、无函数参数、通用空指针 |
| volatile | 禁止编译器优化该变量,变量值可能被硬件/外部程序修改 |
| while | while循环、do-while循环尾部条件判断 |
C99标准
C99新增关键字
C99标准新增5个关键字:inline、restrict、_Bool、_Complex、_Imaginary,各个关键字的含义如下:
| 关键字 | 含义 |
|---|
| inline | 用于指示编译器尽可能地将inline修饰的函数指令在被调用的地方展开 |
| restrict | 用于指针修饰,表明该指针是访问其管理数据的唯一方式 |
| _Bool | C99新增_Bool类型,用于表示布尔值,对应于逻辑值true和false |
| _Complex | 复数类型 |
| _Imaginary | 虚数类型 |
C99新增特性
语法与变量定义
| 特性 | 描述 |
|---|
| // 单行注释标准化 | C89仅编译器扩展,C99正式纳入标准 |
| 代码块任意位置定义变量 | C89仅允许在代码块起始处定义变量 |
| for循环头部定义局部变量 | 在for()内声明变量,作用域仅循环内部 |
| long long / unsigned long long | 64位整型,配套 LL、ULL 数值后缀 |
| 变长数组 VLA | 数组长度使用运行时变量,栈内存分配 |
| 复合字面量 | 临时构造数组、结构体等匿名对象 |
| 指定初始化 | 结构体/数组按成员名赋值,无需按顺序 |
| 灵活数组成员 | 结构体末尾无长度数组,适配动态内存分配 |
| 空大括号零初始化 = {} | 数组、结构体支持空括号整体清零 |
| VLA函数形参 int arr[*] | 变长数组函数声明简写语法 |
| 复合字面量可作为返回值 | 临时结构体、数组可直接return返回 |
| 弱化隐式int规则 | 无返回类型函数默认int被标记为过时写法 |
预处理与编译内置
| 特性 | 描述 |
|---|
| 可变参数宏VA_ARGS | 宏定义支持不定数量输入参数 |
| func内置标识符 | 字符串常量,自动存储当前函数名称 |
| 十六进制浮点常量 | 支持 0x1.2p3 格式浮点数字面量 |
新增标准头文件与类型
| 特性 | 描述 |
|---|
| <stdint.h> | 提供固定位宽整数:uint8_t、int32_t等 |
| <stdbool.h> | 封装 bool、true、false 简化布尔编码 |
| <tgmath.h> 泛型数学库 | 同一函数自动适配 float/double 浮点类型 |
| <wchar.h> 宽字符库 | 统一宽字符、多字节字符转换接口 |
标准库与格式化输出
| 特性 | 描述 |
|---|
| %zu、%td 格式化占位符 | 分别用于打印 size_t、ptrdiff_t 类型 |
| 新增大量数学库函数 | round、erf、tgamma、nearbyint 等浮点函数 |
C11标准
C11新增关键字
C11标准新增7个关键字:Alignas、_Alignof、_Noreturn、_Generic、_Thread_local、_Atomic、_Static_assert,各个关键字含义如下:
| 关键字 | 描述 |
|---|
| Alignas | 内存对齐的操作符,与_Alignof配合使用,指定结构的对齐方式 |
| _Alignof | 获取类型和变量的对齐方式 |
| _Noreturn | 修饰函数,不会返回值 |
| _Generic | 泛型函数 |
| _Thread_local | 线程局部存储,限定了变量不能在多线程之间共享 |
| _Atomic | 原子操作 |
| _Static_assert | 编译期间断言 |
C11新增特性
语法与类型扩展
| 特性 | 描述 |
|---|
| 匿名结构体 / 匿名联合体 | 结构体内部无名称的嵌套结构,可直接访问内层成员,简化协议、寄存器定义 |
| max_align_t | 代表系统基础类型最大对齐粒度,malloc 分配内存默认满足该对齐 |
| 变长数组VLA改为可选特性 | C99强制支持,C11标准改为可选,编译器可选择不实现 |
并发、原子、多线程
| 特性 | 描述 |
|---|
| <threads.h> 多线程标准库 | 标准化线程创建、互斥锁、条件变量、一次性初始化 |
| <stdatomic.h> 原子操作库 | 原子类型、原子读写、内存序,无锁并发编程标准接口 |
| 标准化内存模型 | 定义多线程数据竞争、可见性、执行顺序规则 |
| thrd_t、mtx_t、cnd_t | 线程、互斥锁、条件变量标准类型 |
| call_once 一次性执行 | 保证一段代码在多线程环境仅执行一次,用于单例初始化 |
标准库变更与安全优化
| 特性 | 描述 |
|---|
| 彻底移除 gets() | 存在严重缓冲区溢出漏洞,永久删除,推荐 fgets |
| fopen 新增独占模式 “x” | fopen(“a.txt”, “wx”),文件不存在才创建,防止覆盖已有文件 |
| 新增安全边界字符串函数 | strnlen、strndup 等,限制操作长度避免越界 |
| 快速退出 quick_exit() | 不执行静态对象析构、仅注册atexit_at_quick回调,快速终止程序 |
| at_quick_exit() | 注册 quick_exit 触发时执行的回调函数 |
预处理与兼容性调整
| 特性 | 描述 |
|---|
| 移除隐式函数声明支持 | 调用未声明函数强制警告/报错,杜绝未定义行为 |
| 支持UTF-8字符字面量 u8"" | 原生UTF-8字符串常量,区分于宽字符 |
| 修复复合字面量、初始化边界定义 | 统一数组、结构体初始化未定义填充规则 |
C23标准
C23标准新增关键字
| 关键字 | 功能描述 |
|---|
| nullptr | 标准空指针常量,类型为 nullptr_t,区分整数0 |
| static_assert | 升级为关键字,替代 C11 的_Static_assert,无需头文件 |
| bool | 内置布尔关键字,无需包含<stdbool.h> |
| true | 布尔真值字面量,内置关键字 |
| false | 布尔假值字面量,内置关键字 |
| typeof | 编译期获取表达式/变量的类型,简化泛型代码 |
| loop | 标签循环配套关键字,支持带标签break跳出外层循环 |
相关参考