C++已经问世30多年了。在此期间,很多新的语言来了又走,但是C++经得起考验。今天介绍的这本新书《C++编程自学宝典》背后的一个大问题就是:为什么选择C++?答案就分布于读者将要看到的本书的内容中。但作为一个“搅局者”,C++是一门灵活、强大的语言,并且拥有丰富、庞大的标准库提供支持。
C++一直是一门强大的语言,可以让用户直接访问内存,同时提供大量的高级特性,比如创建新类型和类的能力,以及重载运算符以满足用户需求。然而,更现代的C++标准添加了不少特性:通过模板进行泛型编程,通过函数对象和lambda表达式进行函数式编程。用户可以根据需要充分地利用这些特性,也可以使用抽象接口指针或类C过程代码编写事件驱动代码。
在本书中,我们将介绍C++11规范以及通过该语言提供的标准库。本书使用简短的代码片段解释了如何使用这些特性,每一章包含一个实用示例来解释这些概念。在本书的最后,读者将了解该语言的所有功能以及C++标准库可以实现的功能。假定读者是初学者,本书将引导和提示读者从零开始使用C++。
为什么选择C++?从读者自身的实际情况来看,原因有很多。
读者选择C++可能是因为必须为一个C++项目提供技术支持。在超过30年的生命周期中,该项目中已经包含了数百万行C++代码,并且大部分流行的应用程序和操作系统是使用C++编写的,或者是使用了与之有关的组件和库。几乎不可能找到一台不包含C++代码的电脑
或者读者打算使用C++编写新的代码。这可能是因为项目代码中将会用到一个使用C++编写的程序库,而且有成千上万的程序库可供选择:开源的、共享的和商业软件。
或者读者可能是被C++强大的功能和灵活性所吸引。现代高级程序语言的目标是将程序员从繁复的编程工作中解放出来。同时,C++还允许用户和机器保持尽可能紧密的联系,使得用户可以直接访问计算机内存(有时是比较危险的)。通过类和重载这些语言特性,C++是一门灵活的语言,我们可以对它进行功能扩展,并编写可复用的代码。
不论读者选择C++的理由是什么,这个决定都是非常明智的,本书可以作为读者入门的起点。
本书是一本实用性的书,读者可以对其中的代码输入、编译和运行。为了编译代码,你将需要一个C++编译器和链接器,在本书中它们是指提供Visual C++的Visual Studio 2017社区版程序。选择该编译器是因为我们可以免费下载它,它符合C++标准规范,并且包含大量能够提高编程效率的工具。Visual C++提供了对C++11语言特性的支持,并几乎兼容C++14和C++17的所有语言特性。Visual C++还包含了C99运行时库、C++11标准库和C++14标准库。上述所有规范意味着读者在本书中将要学习的代码,将能够被其他所有标准的C++编译器编译。
本文将从如何获取和安装Visual Studio 2017社区版程序的细节开始。如果你已经拥有了一个C++ 编译器,那么可以跳过本小节。本书大部分内容是与编译器和链接器无关的。但是第10章介绍调试和诊断技术时会涉及一些专属于Microsoft的功能特性。Visual Studio是一款功能齐全的代码编辑器,所以即使你不使用它来管理项目文件,也仍然会发现它对于编辑代码来说是非常有用的。
在介绍完程序安装之后,读者将学习一些C++的基础知识:如何组织源码文件和项目,以及如何管理可能存在几千个文件的项目。
最后,本文将以一个循序渐进的结构化示例作为结尾。这里读者将学习如何使用C++标准库编写简单的函数以及一种管理项目文件的机制。
C++的前身是C语言,C语言是由Dennis Richie供职于贝尔实验室时设计的,于1973年首次发布。C语言曾经广受青睐,并且用于编写早期的Unix和Windows版本。事实上,大部分操作系统的程序库和软件开发包仍然包含C语言接口。C语言功能很强大,因为使用它编写的代码可以被编译成一种紧凑格式,它采用了静态类型系统(因此编译器可以进行类型检查),并且该语言的类型和结构支持直接访问内存的计算机架构。
不过C语言是过程式的并且基于函数,虽然它包含能够封装数据的记录类型(struct),但是它不包含类似对象的行为来表现被封装的状态。显然,用户迫切希望有一种语言既拥有C语言的强大功能,又拥有面向对象的类的灵活性和可扩展性,也就是一种支持类的C语言。1983年,Bjarne Stroustrup发明了C++,++符号来自C语言的增量运算符++。
严格来说,在作为变量后缀时,++运算符表示变量执行自增操作,但返回的变量值是它执行自增操作之前的。因此在C语言代码语句“int c = 1; int d = c++;”当中,变量d获得的返回值是1,变量c的值是2。从这一点来看,它并没有明确地表达C++是C的增量这一理念。
严格来说,在作为变量后缀时,++运算符表示变量执行自增操作,但返回的变量值是它执行自增操作之前的。因此在C语言代码语句“int c = 1; int d = c++;”当中,变量d获得的返回值是1,变量c的值是2。从这一点来看,它并没有明确地表达C++是C的增量这一理念。
C++项目中可以包含几千个文件,并且管理这些文件甚至可以成为一个单独的工作任务。当构建项目时,如果应该编译某个文件,那么选择哪种工具编译它?文件应该按照什么顺序编译?这些编译器生成的输出结果又是什么?编译后的文件应该如何组织到一起构造可执行文件?
编译器工具还拥有大量的选项,比如调试信息、优化类型、为多种语言特性提供支持以及处理器特性。编译器选项的不同组合将会用于不同场景(比如版本构建和版本调试)。如果用户是在命令行上执行编译任务的,那么务必确保选择了正确的选项,并在编译所有源代码的过程中始终应用它们。
文件和编译器选项的管理可以变得很复杂。这也是用户应该使用一款构建工具处理即将上线的产品代码的原因。与Visual Studio一起安装的构建工具有:MSBuild和nmake两款。当用户在Visual Studio环境下构建一个Visual C++项目时,将使用MSBuild,并且会把编译规则存放在一个XML文件中。用户甚至可以在命令行中调用MSBuild,将XML项目文件传递给它。nmake是Microsoft在多个编译器之间维护程序多个版本的实用性工具。在本文中,读者将学习如何充分利用nmake的实用性编写一个简单的makefile文件。
在介绍项目管理的基础知识之前,我们必须先了解用户通常会在C++项目中找到哪些文件以及编译器会如何处理这些文件。
编译器
C++是一门高级程序语言,旨在为用户提供丰富的语言特性,以及为用户和其他开发人员提供良好的可读性。计算机的处理器执行底层代码,并且这也是编译器将C++代码转化成处理器的机器码的主要目的。单个编译器也许可以兼容多种处理器,如果代码是符合C++规范的,那么它们还可以被其他编译器编译,以便兼容其他处理器。
不过,编译器的功能远不止于此。C++允许用户将代码分割成若干函数,这些函数可以接收参数并返回一个值,因此编译器可以配置内存来传递这些数据。此外,函数可以声明只在函数内部使用的变量,并且它将只在函数被调用时才存在。编译器配置的内存称为栈帧(stack frame)。编译器中包含如何创建栈帧的选项,比如Microsoft的编译器选项/Gd、/Gr和/Gz决定了函数参数被推送到堆栈上的次序,以及调用方函数或被调用函数在调用结束时是否应该从堆栈中移除这些参数。当我们编写的代码需要和其他人共享时,这些选项将非常重要(不过基于本书的目的,应该会使用默认的堆栈结构)。这只是冰山一角,不过编译器选项为用户提供的强大功能和灵活性应该会让读者印象深刻。
编译器编译C++代码,如果遇到代码中的错误,将向用户发送编译器错误提示信息。它是对代码的语法检查。这对于确保用户从语法角度编写完美的C++代码非常重要,不过这仍然可能是在做无用功。编译器的语法检查对于检查代码来说非常重要,不过用户应该总是使用其他方法检查代码。比如下列代码声明了一个整数类型变量并为它赋值:
int i = 1 / 0;
编译器将向用户提示C2124错误:divide or mod by zero(除数不能为0)。不过,下列代码将使用额外的变量执行相同的操作,但是编译器不会报错:
int j = 0;
int i = 1 / j;
当编译器提示出现错误时将停止编译。这意味两件事:首先,你将无法得到编译输出结果,因此将不会在一个可执行文件中找到该错误;其次,如果源代码中存在其他错误,我们只有在修复当前错误重新编译代码时才会发现它。如果你希望对代码执行语法检查并退出编译,可以使用/Zs选项开关。
编译器还会生成警告信息。一个警告意味着代码将被编译,但是代码中的某个问题可能会对生成的可执行文件产生潜在的不良影响。Microsoft编译器将警告分为4个级别:级别1是最严重的(应该立刻解决),级别4是信息性的。警告通常用于向用户声明被编译的语言特性可以正常运行,不过它需要的某个特定编译器选项,开发者并没有使用。
在开发代码期间,我们将会经常忽略警告信息,因为这可能是在测试某些语言特性。
不过,当开发的代码准备上线发布时,你最好对警告信息多加留意。默认情况下,Microsoft编译器将显示1级警告信息,你可以使用/W选项和一个数字来声明希望看到的警告信息级别(比如,/W2表示用户希望看到2级警告以及1级警告)。在正式上线的产品代码中,你可能会使用/Wx选项,这是告知编译器将警告信息也当作错误来看待,我们必须修复所有问题,以便能够顺利编译代码。你还可以使用pragma编译器(pragma的概念将稍后介绍),并且编译器的选项还可以忽略特定警告信息。
链接代码
编译器将生成一个输出。对于C++代码来说,这将是对象代码,不过你可能还会得到一些其他的编译器输出,比如被编译的资源文件。对于它们自身来说,这些文件无法被执行,尤其是操作系统需要设置特定的结构时。一个C++项目将始终包含两个阶段:先将源代码编译成一个或者多个对象文件,然后将这些对象文件链接到一个可执行程序中。这意味着C++编译器将提供另外一种工具,即链接器。
链接器也有决定它如何工作并指定输出和输入的选项供用户选择,并且它还会向我们发出错误和警告信息。与编译器类似,Microsoft的链接器也有一个选项/WX,它可以将预览版程序中的警告信息当作错误来处理。
本文摘自《C++编程自学宝典》
《C++编程自学宝典》
[英]理查德·格里姆斯 著
本书旨在通过全面细致的内容和代码示例,带领读者更加全方位地认识C++语言。全书内容共计10章,由浅入深地介绍了C++的各项特性,包括C++语法、数据类型、指针、函数、类、面向对象特性、标准库容器、字符串、诊断和调试等。本书涵盖了C++11规范及相关的C++标准库,是全面学习C++编程的合适之选。
邀请10名好友关注异步图书10天,即可免费获得异步新书。
点击阅读原文,直接购买《C++编程自学宝典》
阅读原文