文章目录
概述
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跳出外层循环 |
相关参考
- 《C Primer Plus》
- 《C语言深度剖析》