C++历史和标准

简要回顾 C++的起源:

  1. 1979 年,Bjarne Stroustrup(C++之父)受到 Simula 语言(首个支持面向对象的语言)的启发,将面向对象的语法和 C 语言结合,得到了最早版本的"C with Classes",它提供面向对象的基本语法,然后先翻译成 C 的源码进一步进行处理。
  2. 1983 年,这个新语言正式被命名为 C++。许多重要的特性被加入,包括引用机制(符号为&)、虚函数、函数重载、const 关键字等。
  3. 1985 年,Stroustrup 的 C++参考手册《C++ Programming Language》出版,此时并没有 C++语法规范,只有这份参考手册。
  4. 1998 年,C++标准委员会发布了 C++语言的第一个国际标准:C++98。最早的标准模块库(Standard Template Library,STL)也被纳入了该版标准。

C++的主要标准:

  1. C++98: 第一个标准。
  2. C++03: C++98 的修订版。
  3. C++11: C++98之后最重要的一个标准,它带来了巨大的变革,此后的 C++称为 Modern C++。
  4. C++14: C++11 的修订版。
  5. C++17: C++11 的再次修订版。
  6. C++20: 在 C++11 之后又一个巨大变革,包括 module、concept 等,但尚未被主流编译器完整地实现,广泛应用更为时尚早。
  7. C++23: ...

明显可以把C++的语法标准划分为三代:C++11之前,C++20之前,C++20之后。

以gcc为例,不同的编译器对最新语法的完整支持大致如下:

  • C++11:完整支持在 GCC 4.8 及以上版本;
  • C++14:完整支持在 GCC 5.1 及以上版本;
  • C++17:完整支持在 GCC 8 及以上版本;
  • C++20:大部分支持在 GCC 11,进一步支持在 GCC 12 及之后版本,实际上到目前都没有完整支持。

可以使用下面的选项指定它采用某个语法标准(当然存在支持标准的上限,因为标准在不断更新):

  • 自 VS2017 开始,可以使用编译选项指定语法标准:/std:c++11 /std:c++17 /std:c++20 /std:c++latest
  • 对于 gcc 和 clang,对应的选项为-std=c++11 -std=c++17 -std=c++20

缺省时编译器会采用默认的语法标准,仍然以gcc为例,默认语法标准与编译器版本对应如下:

  • gcc 4.x 以及更早的版本,默认使用 C++98
  • gcc 5.1 开始默认使用 C++14
  • gcc 11.1 开始默认使用 C++17

注意,编译器自己实现的内容和语法标准规定的内容并不是严格的对应关系,可能存在:

  1. 语法标准规定的,但编译器没有完整实现;
  2. 语法标准不涉及的,主流编译器普遍实现的内容。
  3. 语法标准不涉及的,但是某个编译器独自实现了,即编译器的特性。

学习时建议基于 C++17 标准,因为 C++17 已经被主流编译器的较新版本完整实现并默认支持。对于更新的语法标准,简要了解尝试即可,因为编译器的实现并不完整,而且需要开启特定的编译选项。 鉴于 C++17 只是 C++11 的修订版,常见的教程或书籍主要是基于 C++11 的,因此可以先学习 C++11,然后学习 C++17 修订增加的部分。(2023-8-4)

C++在线资源

  • cpp reference:C++语法参考手册网站,包括非常多的语法标准细节。
  • cpp compiler support: 不同编译器对 C++的语法标准的支持情况。
  • cpp insights:Cpp 代码查看平台,支持众多编译器,可以把模板、lambda 以及其它语法糖,翻译为更本质的形式。
  • cpp compiler explorer:Cpp 编译运行平台,支持众多编译器,可以查看对比汇编文件,也可以编译运行。
  • cpp quiz:Cpp 在线答题,包含很多语法方面的判断题(不是 leetcode 那种编程题),出题角度很刁钻,适合深入理解 C++语法。
  • cpp benchmark:Cpp 函数基准测试平台
  • Awesome C++: 很棒的 C/C++ 框架、库、资源精选列表,不是 Github 仓库,而是独立网站
  • Modern CMake Modern CMake 教程
  • cpp 在线编译器:提供包括C++在内的常见语言在线编译

C++书籍

  1. C++ Primer: 基础教程,注意它和 C++ Primer Plus 没有关系,后者不是它的进阶版,反而更加基础,适合入门。
  2. Effective C++,Effective Modern C++:改善 C++程序与设计的 55 个具体做法。
  3. C++模板元编程实战(李伟):一个基于模板元编程的深度学习框架的初步实现。
  4. C++20 高级编程(罗能)

C++编译器

这里只列出三家最主流的编译器:

  1. GCC (g++), GNU Project
  2. Clang (clang++), LLVM Project
  3. Visual C++ (cl), Microsoft

对于 Windows 平台和 Unix-like 平台的支持:

  1. GCC (g++): 原生支持 Unix-like 平台,对于 Windows 平台的支持需要借助一些辅助方式,例如 MinGW,MSYS2,Cygwin,Windows Subsystem for Linux (WSL)。
  2. Clang (clang++): 原生支持 Unix-like 平台。
  3. Visual C++ (cl): 原生支持 Windows 平台。

除此之外还有 Intel 的 icc 等其它编译器。

C++ 不包含 C

C语言和C++的关系是紧密且复杂的:

  • C++通常可以视作C语言的扩充:直接支持绝大部分的C语言语法,很多C语言的源代码无需任何修改都可以使用C++编译器顺利编译;
  • 主流的C语言编译器实际上都是C/C++编译器,C语言和C++只是编译器的两种处理模式而已。

但是严格来说,C语言和C++在很多细节上是存在差异的,C++并没有选择无条件兼容所有C语言的语法,只是兼容了主要的语法。 有些在C语言中合法的代码在C++中却是不合法的,会导致编译错误;或者即使顺利编译,在运行时也会产生不一样的结果。

第一个例子是关于无参数函数的差异

1
2
3
4
5
6
7
8
#include <stdio.h>

void func(){}

int main(){
func(1);
return 0;
}

这段代码视作C语言可以顺序编译;但是视作C++则编译报错。 因为在C语言中void func();允许接收任意多个任意类型的参数,而void func(void);才是不允许接收任何参数。 在C++中因为已经提供了更完整的类型体系,在语法上会将这两种写法视作一致。

第二个例子是关于函数返回值类型的差异

1
2
3
4
5
6
7
8
#include <stdio.h>

func(){}

int main(){
func();
return 0;
}

这段代码视作C语言可以顺序编译;但是视作C++则编译报错。 因为C语言允许缺省返回值类型(默认视作int),但是C++不允许缺省。

第三个例子是关于字符字面量的差异

1
2
3
4
5
6
#include <stdio.h>

int main(){
printf("%ld",sizeof('a'));
return 0;
}

这段代码视作C语言进行编译,程序会输出4;但是视作C++进行编译,程序会输出1。这是因为两种语言对于字面量的sizeof规定有所不同。

C++与其它语言对比

在主流的几十种编程语言中,C++被认为是最复杂的语言之一,它具有多种编程范式,支持非常多的语法特性,可以被至少视为如下几部分的联邦:

  1. C 语言基本部分;
  2. Object-Oriented C++,即所谓的 "C with classes";
  3. Template C++(模板泛型编程),以及由此产生的 Template metaprogramming(TMP,模板元编程);
  4. Standard Template Library(STL,即 C++模板标准库)。

C++与其它语言的对比可以参考下图,C/C++是弱类型的静态语言,具体的语言对比是一个很大的问题,这里不作讨论。