您提到的“1002”可能是一个笔误,C 语言的国际标准编号是 ISO/IEC 9899,而 C99 是这个标准的第二个主要版本,编号正是 ISO/IEC 9899:1999。
下面我将从历史发展、核心特性、重要意义以及后续版本等方面,全面介绍 C 语言标准。
C 语言标准的演进
C 语言的发展史就是一部标准化的历史,标准化工作旨在统一不同编译器对 C 语言特性的实现,提高代码的可移植性。
-
K&R C (1978)
- 这是 C 语言的第一个非正式标准,由 Brian Kernighan 和 Dennis Ritchie 合著的 The C Programming Language (简称 K&R) 一书定义。
- 它是事实上的标准,但存在一些模糊和二义性。
-
ANSI C / C89 (1989)
- 为了解决 K&R C 的模糊性,美国国家标准协会 制定了第一个官方 C 语言标准,通常称为 C89。
- 它首次将 C 语言标准化,引入了函数原型、
void类型、更严格的类型检查等。 - 后来被国际标准化组织 采纳,称为 ISO/IEC 9899:1989,也就是 C89。
-
C90 (1990)
这是 C89 的国际版,内容基本相同,我们常说的 C89 和 C90 可以视为同一个标准。
-
C95 (1995)
- 这是一个技术勘误和补充版本,正式名称为 ISO/IEC 9899:1990/Amd 1:1995。
- 主要增加了宽字符支持、国际化函数(如
wchar_t,mblen)等,但对语言核心改动不大。
-
C99 (ISO/IEC 9899:1999) - 您问题的核心
这是 C 语言发展史上一次重大的飞跃,带来了大量现代化、便利化的特性,它被广泛认为是 C 语言的“第二个黄金时代”。
-
C11 (ISO/IEC 9899:2011)
在 C99 的基础上进行了改进,主要增加了多线程支持、泛型选择、原子操作等,以及对 C++ 的一些兼容性改进。
-
C17 / C18 (ISO/IEC 9899:2025)
这主要是对 C11 的勘误和修正,没有引入新的语言特性,C17 是一个主要的发布版本,C18 是一个技术勘误版本,C17 是最广泛支持和推荐的稳定标准。
C99 (ISO/IEC 9899:1999) 的核心特性详解
C99 标准对 C89/C90 做了超过 140 处的修改和增强,极大地提升了 C 语言的可用性和表现力,以下是其最重要的特性:
变量声明可以放在代码块的任意位置
这是 C99 最广为人知的特性之一,在 C89 中,所有变量必须在一个函数的开头(代码块顶部)声明,C99 允许在需要时再声明变量,使得代码逻辑更清晰。
// C89 风格
void func_c89() {
int i;
float f;
char c;
for (i = 0; i < 10; i++) {
// ...
}
}
// C99 风格 - 更清晰
void func_c99() {
for (int i = 0; i < 10; i++) {
float f = (float)i / 3.0f; // 在需要时才声明
// ...
}
// int i 在这里已经超出作用域
}
复合字面量
允许你创建一个匿名的结构体、数组或联合体并初始化它,而无需先定义一个变量。
// 创建一个包含 {1, 2, 3} 的数组,并将其地址赋给指针
int *ptr = (int[]){1, 2, 3};
// 创建一个结构体字面量
struct point {
int x, y;
};
struct point p = (struct point){10, 20};
风格的单行注释
C89 只支持 风格的多行注释,C99 引入了 C++ 风格的单行注释,提高了代码的可读性。
// 这是一个单行注释,在 C99 中是合法的 int a = 5; /* 这也是一个注释 */
变长数组
允许在运行时确定数组的大小,这是一个强大的特性,但需要小心使用,因为它可能导致栈溢出。
void create_array(int size) {
// VLA,数组大小在运行时确定
int vla[size];
for (int i = 0; i < size; i++) {
vla[i] = i * i;
}
}
long long 和 long double 类型
引入了至少 64 位的 long long 整数类型和更高精度的 long double 类型,以满足大数计算的需求。
long long big_number = 9223372036854775807LL; long double high_precision = 3.14159265358979323846L;
指针算术的增强
允许对 void* 类型的指针进行算术运算,这在 C89 中是不允许的。
void *ptr = malloc(100 * sizeof(int)); // C99 允许这样做 ptr += 10; // 将指针向后移动 10 个字节
指定初始化器
允许你通过索引来初始化数组和结构体的特定成员,而不用按顺序初始化所有成员。
// 数组初始化
int arr[10] = {0, [5] = 5, [9] = 9}; // arr[5]=5, arr[9]=9, 其他为0
// 结构体初始化
struct point p = { .y = 20, .x = 10 }; // 按成员名初始化,顺序无关
_Bool 和 <stdbool.h>
引入了布尔类型 _Bool,为了方便,标准库 <stdbool.h> 将其定义为 bool,并定义了 true 和 false 宏。
#include <stdbool.h>
bool is_ready = false;
if (is_ready) {
// ...
}
浮点数的 注释
虽然单行注释是通用特性,但 C99 明确规定,在浮点数字面量后可以跟 注释,而中间不能有空格,这是一个非常细节的改进。
double d = 0.1// 这是一个注释 .2; // d 的值是 0.12
新增和修改的库函数
C99 增加了大量的数学函数(如 fma, expm1)、浮点环境函数(feclearexcept)和宽字符处理函数等。
C99 的重要意义
- 现代化 C 语言:C99 将 C 语言从 70 年代的风格带入了 90 年代,使其功能更强大、更符合现代编程习惯。
- 提高可读性和可维护性:允许在任意位置声明变量、使用单行注释和指定初始化器,都让代码更容易编写和理解。
- 增强表达能力:复合字面量、VLA、
long long等特性让 C 语言能够更灵活地处理复杂数据结构和计算任务。 - 成为事实标准:虽然 C89 在很长一段时间内仍是主流(微软的 MSVC 直到 2025 年才完全支持 C99),但 C99 已被 GCC、Clang、ICC 等主流编译器广泛支持,并成为 Linux 内核、许多开源项目和教学中的事实标准。
后续标准简介
-
C11 (2011):
- 多线程:引入了
_Atomic关键字、<threads.h>和<stdatomic.h>库,为 C 语言带来了原生线程支持。 - 泛型选择:通过
_Generic宏,实现了类似泛型函数的功能,可以根据参数类型执行不同的代码。 - 静态断言:
_Static_assert,允许在编译时检查条件,如果条件不满足则编译报错。 - 匿名结构体/联合体:允许在一个结构体内部直接定义另一个匿名结构体/联合体,其成员可以直接被外部结构体访问。
- 多线程:引入了
-
C17/C18 (2025):
主要工作是修复 C11 标准中的缺陷(勘误),并没有引入新的语言特性,它是一个稳定、可靠的版本,是目前推荐使用的标准。
| 标准 | 关键词/主要特性 | 状态/备注 |
|---|---|---|
| C89/C90 | 函数原型、void、标准库 |
历史基础,很多旧项目仍在使用 |
| C95 | 宽字符支持、国际化 | 较小的补充 |
| C99 | 任意位置声明变量、VLA、long long、单行注释、指定初始化器 |
里程碑式版本,现代 C 语言的基石 |
| C11 | 多线程、原子操作、泛型选择、静态断言 | 引入了并发编程等高级特性 |
| C17/C18 | 勘误和修正,无新特性 | 当前最稳定、最推荐的标准 |
对于现代 C 语言开发者来说,C99 是必须掌握的核心标准,虽然 C11 和 C17 带来了更多新特性,但 C99 引入的语法和思想已经深刻地影响了整个 C 语言生态,了解 C99,是理解和使用现代 C 编程的必备知识。
