Skip to content

C++ 标准的版本与演进

前标准化时代

C++ 是一门古老的编程语言,诞生于 1979 年。贝尔实验室的本贾尼·斯特劳斯特卢普(Bjarne Stroustrup)在 C 语言的基础上增加了若干特性,将其命名为“C with Classes”,1982 年改名为 C++,意为“C的增强版”。

C++ 很快取得了巨大的成功。然而,在诞生早期,它并没有统一的标准,各个编译器厂商(比如微软、Borland)各自实现了自己的版本,所支持的语法规则存在一定的差异,导致代码的可移植性很差。一直到 1998 年,国际标准化组织(ISO)终于发布了 C++ 的第一个正式标准,代号 ISO/IEC 14882:1998,通称 C++98

与此同时,美国国家标准协会(ANSI)也采纳了这个标准。因此,早期的许多材料都喜欢用 "ANSI C++" 这个词来强调“这是标准化的 C++,不是厂商的方言”。

INFO

尽管 C++ 早在 1998 年就完成了标准化,但 C++98 之前的古董写法在此后仍然统治了中国高校的计算机教育二十余年。这可能是由于 1998 年微软的 C++ 编译器 Visual C++ 6.0 的的广泛流行、谭浩强出品的教材《C++程序设计》被普遍采用和二次改编、以及高校教师缺乏更新教学内容的动力。

如果你看到了类似这样的写法,请和我一起为过时教育体系的受害者默哀:

C++
#include <iostream.h>

void main() {
    cout << "Hello world!" << endl;
}

在 2003 年,ISO 还发布了一版 C++ 标准(称为 C++03),它主要是对 C++98 中一些不准确描述的修补,没有引入新内容。

现代 C++

“C++0x”

伴随着软件工程理论的进步与实践经验的积累,C++ 也在不断进行自我迭代与革命。2011 年,它迎来了一次史诗级的更新:C++11。它引入了大量新特性(比如 auto 自动类型推导、智能指针、lambda 表达式、右值引用与移动语义、多线程标准库等等),让 C++ 变得更安全、更简洁、更像现代语言。业界通常把 C++11 及其以后的版本称为“现代 C++(Modern C++)”。

在开始着手标准更新工作时,C++标准委员会认为它一定能在 21 世纪的第一个十年完成,于是给它的代号是 C++0x(x 作为占位符,等完成的时候填进去)。

当然,如大家所见,标准委员会在漫长地争吵、拉锯之后,一直到 2011 年才完成修订工作。不过,虽然迟到了,但他们表示 “C++0x” 这个代号仍然可以使用:在 C++ 中,0x 用来标识一个十六进制数,因此只要没有拖到 2016 年,这个代号就是准确的!

稳定迭代

吸取了 C++11 拖延太久的教训,标准委员会决定在此以后每 3 年发布一个版本。于是,我们现在看到了非常规律的版本号:C++14、C++17、C++20、C++23,以及即将发布的 C++26。

C++11 标准正式发布之前,编译器开发者在实现其已经确定的部分特性时使用的是 C++0x 这个代号。使用代号去表示“未来的 C++ 标准”也成为了被继承的传统:每次向后递推一个字母。因此,C++14 又称 C++1y、C++17 又称 C++1z、C++20 又称 C++2a,依此类推。

附录:“C++ 标准”究竟是什么?

如果不使用任何比喻,C++ 标准就是一份厚达 1800 多页的 PDF 电子文档。这份文档里全是枯燥的法律条文般的描述,它不包含任何可执行程序。它只做一件事:规定 C++ 应该长什么样。具体来说,它规定了 C++ 的全部语法规则,同时规定了编译器应该提供哪些现成的工具(标准库)。

标准更新可能会引入新的语法、工具,也可能会废弃旧的工具:

C++

// C++98/03 的变量声明:
int x = 42;
double y = 42.0;

// C++11 新引入,可以不用明确写出类型,自动推断:
auto x = 42; // x 类型为 int
auto y = 42.0;

// C++98/03 可用,读取一行字符到字符数组中
// 由于这个代码必然存在缓冲区溢出(Buffer Overflow)漏洞,C++11 废止了 gets 这个函数的使用 
char buf[64];
gets(buf);

C++ 标准不是具体的编译器,而是编译器共同遵守的“约定”。标准允许编译器在部分语言细节上存在差异——本课程的学习过程中必然会有体会。对于一些代码,标准可能将其约定为“实现定义(Implement-defined)/未指明(Unspecified)”,允许编译器在规则范围内自行决定其行为;或规定其为“未定义(Undefined)”,表示这个代码是错误、不符合标准的,编译器可以执行任意操作。

关于标准中为何要有这种看似奇怪的规定,有一篇非常深入的 讨论,但所需求的背景知识超出了初学者的范围。

部分国内高校的编程教学可能会执着于讨论乃至于考查一些未定义行为的结果,这是无意义的:

C++
#include <iostream>
using namespace std;

int main() {
    int i = 3;
    // Visual Studio 2026 中输出9,小熊猫(gcc15)中输出16
    cout << i++ + i++ + i++ << endl;
    return 0;
}