跳转到内容

C++ 编程

来自维基教科书,开放的书籍,开放的世界

编译器

[编辑 | 编辑源代码]

一个 编译器 是一个将用一种 计算机语言源代码)编写的 计算机程序 翻译成等效的用计算机的原生 机器语言 编写的程序的程序。这个翻译过程,包括几个不同的步骤,被称为 编译。由于编译器本身就是一个程序,用计算机语言编写,所以这种情况似乎是一个悖论,类似于 先有鸡还是先有蛋 的困境。编译器可能不是用最终可编译的语言创建的,而是用之前可用的语言或甚至用机器代码创建的。

编译器的 编译 输出是翻译或 编译 程序的结果。输出中最重要的一部分保存到一个名为 目标文件 的文件中,它包含将源文件转换为目标文件的转换。

注意
某些文件可能需要创建/用于成功编译。该数据不是 C++ 语言的一部分,可能是外部代码编译的结果(例如库)。这可能取决于您使用的特定编译器(例如,MS Visual Studio 会为项目添加一些额外的文件),在这种情况下,您应该查看文档。该数据也可以是需要访问的特定框架的一部分。请注意,这些构造中的某些构造可能会限制代码的可移植性。

然后,如果目标文件是可执行格式,计算机可以运行(执行)该 编译 程序的指令。但是,编译还需要额外的步骤:预处理和链接。

编译时

[编辑 | 编辑源代码]

定义编译器在构建(创建)程序(可执行或不可执行)期间执行的时间和操作(即 编译时操作)。C++ 语言中“static”的大多数用法与编译时信息直接相关。

编译时执行的操作通常包括 词法分析语法分析、各种类型的 语义分析(例如,类型检查、一些 类型转换模板实例化)以及 代码生成

编程语言的定义将指定源代码必须满足的编译时要求才能成功编译。

编译时发生在 链接时(将一个或多个编译文件的输出连接在一起)和运行时(程序执行时)之前。在一些编程语言中,可能需要在运行时进行一些编译和链接。

运行时

运行时执行时间 从程序开始执行的那一刻开始,到程序退出时结束。在这个阶段,编译器无关紧要,没有控制权。这是关于优化的最重要的位置(程序只编译一次,但运行很多次)和调试(跟踪和交互只有在这个阶段才能实现)。但运行时也是一些 类型转换可能发生 的地方,运行时类型信息 (RTTI) 与此相关。运行时的概念将在相关时再次提及。

词法分析
[编辑 | 编辑源代码]

这也被称为扫描或 标记化。它发生在语法分析之前,并将代码转换为 标记,这些标记是程序实际使用的代码部分。源代码以字符(排列在行上)的形式表达为每个保留关键字的特殊标记序列,以及数据类型和标识符以及值的标记。词法分析器是编译器的一部分,它从源代码中删除空格和其他不可编译字符。它使用空格来分隔不同的标记,并忽略空格。

为了简单说明这个过程

int main()
{
    std::cout << "hello world" << std::endl;
    return 0;
}

根据使用的词法规则,它可能被 标记化

1 = string "int"
2 = string "main"
3 = opening parenthesis
4 = closing parenthesis
5 = opening brace
6 = string "std"
7 = namespace operator
8 = string "cout"
9 = << operator
10 = string ""hello world""
11 = string "endl"
12 = semicolon
13 = string "return"
14 = number 0
15 = closing brace

因此,对于这个程序,词法分析器可能会发送类似的东西

1 2 3 4 5 6 7 8 9 10 9 6 7 11 12 13 14 12 15

给下一个将要解析的语法分析器。当它可以处理数值并能够区分语言语法(例如分号)和所有其他内容时,语法分析器更容易应用语言规则,并且知道每个事物的数据类型。

语法分析
[编辑 | 编辑源代码]

此步骤(有时也称为语法检查)确保代码有效,并将按顺序组成可执行程序。语法分析器将规则应用于代码,检查以确保每个左括号都有一个对应的右括号,每个声明都有一个类型,以及该类型存在,以及……语法分析比词法分析更复杂 =)。

例如

int main()
{
    std::cout << "hello world" << std::endl;
    return 0;
}
  • 语法分析器将首先查看字符串“int”,将其与定义的关键字进行比较,并发现它是一个整数类型。
  • 然后,分析器会将下一个标记视为标识符,并检查以确保它使用的是有效的标识符名称。
  • 然后它将查看下一个标记。因为它是一个左括号,所以它将“main”视为一个函数,而不是一个变量声明(如果它找到一个分号)或一个整数变量的初始化(如果它找到一个等号)。
  • 在左括号之后,它将找到一个右括号,这意味着该函数有 0 个参数。
  • 然后它会查看下一个标记,发现它是一个左大括号,所以它会认为这是函数 main 的实现,而不是 main 的声明(如果下一个标记是分号的话),即使在 C++ 中不能声明 main。它可能还会创建一个计数器来跟踪语句块的级别,以确保括号成对出现。*之后它会查看下一个标记,可能不会对其进行任何操作,但然后它会看到 :: 运算符,并检查 "std" 是否是一个有效的 命名空间
  • 然后它会看到下一个标记 "cout" 作为 "std" 命名空间 中标识符的名称,并发现它是一个模板。
  • 分析器会看到下一个标记 << 运算符,因此它会检查 << 运算符是否可以与 cout 一起使用,以及下一个标记是否可以与 << 运算符一起使用。
  • 下一个标记 ""hello world"" 后面的标记也会发生同样的事情。然后它会再次遇到 "std" 标记,查看它后面的 :: 运算符标记,并检查 命名空间 是否再次存在,然后检查 "endl" 是否在 命名空间 中。
  • 然后它会看到分号,所以它会将其视为语句的结束。
  • 接下来它会看到关键字 return,然后期望下一个标记是一个整数值,因为 main 返回一个整数,它会找到 0,这是一个整数。
  • 然后下一个符号是分号,所以这是语句的结束。
  • 下一个标记是右大括号,所以这是函数的结束。并且没有更多标记了,所以如果语法分析器没有在代码中发现任何错误,它会将标记发送给编译器,以便程序可以被转换为机器语言。

这只是语法分析的一个简单视图,真正的语法分析器并不真正以这种方式工作,但其思想是相同的。

以下是一些语法分析器会查找的关键字,以确保您没有将它们用作标识符名称,或者了解您正在定义的变量类型或正在使用的函数,这些函数包含在 C++ 语言中。

编译速度

[edit | edit source]

有几个因素决定了编译的速度,例如

  • 硬件
    • 资源(慢速 CPU、内存不足,甚至慢速 HDD 都会有影响)
  • 软件
    • 编译器本身,新的总是更好,但可能取决于您希望项目移植到什么程度。
    • 为程序选择的方案(对象依赖结构、包含)也会起作用。

经验表明,如果您遇到编译速度慢的问题,您尝试编译的程序设计很差,花点时间构建自己的代码以最大程度地减少更改后的重新编译。大型项目总是编译速度更慢。使用预编译头文件和外部头文件保护。我们将在本书的 优化 部分讨论减少编译时间的方法。

哪里可以获得编译器

[edit | edit source]

在选择编译器时,您必须考虑您的系统操作系统、个人偏好以及您在使用它时可以获得的文档。

如果您没有、不想或不需要在机器上安装编译器,可以使用 http://ideone.com(或 http://codepad.org,但您需要更改代码以不需要交互式输入)上的 WEB 免费编译器。如果您需要,您总是可以在本地获得一个。

有很多编译器,甚至更多的 IDE 可用,有些是免费的和开源的。IDE 通常会将所需的编译器包含在安装中(GCC 是最常见的)。

GCC 是最成熟、最兼容的 C++ 编译器之一,也称为 GNU 编译器集合。它是一套由自由软件基金会开发的免费编译器,理查德·斯托曼是主要架构师之一。

互联网上有许多不同的预编译 GCC 二进制文件;下面列出了一些流行的选择(以及详细的安装步骤)。您可以在 GCC 网站上轻松找到有关如何在其他操作系统上执行此操作的信息。

注意
编译器通常是用 C 语言实现的(因为它通常是系统语言,在汇编语言之上,新的系统会实现它)。GCC 最终在 2005 年 5 月底,获得绿灯开始将核心代码库迁移到 C++。考虑到这是最常用的编译器,也是一个开源实现,对于编译器和语言本身来说,这是一个非常积极的步骤。

IDE(集成开发环境)

[edit | edit source]
GTK2 下的图形化 Vim

集成开发环境 是一种软件开发系统,它通常将编辑器、编译器和调试器集成在一个一起分发的集成包中。有些 IDE 需要用户自己进行组件集成,而另一些则将 IDE 称为他们用于编程的一组独立工具。

一个好的 IDE 是一个允许程序员使用它来抽象和加速一些更常见任务,同时在阅读和管理代码方面提供一些帮助的 IDE。除了编译器之外,C++ 标准对不同的实现没有控制。大多数 IDE 都是面向视觉的,尤其是新的 IDE,它们将提供图形调试器和其他视觉辅助工具,但有些人仍然喜欢像 VimEmacs 这样的强大文本编辑器提供的视觉简洁。

在选择 IDE 时,请记住,您也在投入时间来精通它的使用。完整性、稳定性和跨操作系统的可移植性将非常重要。

对于 Microsoft Windows,您还有 Microsoft Visual Studio Community(最新版本 2019),目前可以免费获得,并且包含大多数功能。它包含一个 C++ 编译器,可以从命令行或提供的 IDE 中使用。

在本书的 附录 B:外部参考 中,您将找到对可以使用的其他免费编译器和 IDE 的引用。

在 Windows 上
[edit | edit source]

Cygwin

  1. 转到 http://www.cygwin.com 并单击页面右上角的“立即安装 Cygwin”按钮。
  2. 在弹出的窗口中单击“运行”,然后多次单击“下一步”,接受所有默认设置。
  3. 当该窗口弹出时,选择任何下载站点(“ftp.easynet.be”等);按“下一步”,Cygwin 安装程序应开始下载。
  4. 当“选择包”窗口出现时,向下滚动到“Devel”标题,并单击它旁边的“+”。在现在显示的包列表中,向下滚动并找到“gcc-c++”包;这是编译器。单击“跳过”一词一次,它应该更改为类似“3.4”之类的数字(版本号),并且“gcc-core”以及现在将要下载的几个其他必需包旁边会出现一个“X”。
  5. 单击“下一步”,编译器以及 Cygwin 工具应开始下载;这可能需要一段时间。在等待的同时,转到 http://www.crimsoneditor.com 并下载该免费程序员编辑器;它功能强大,但对于初学者来说易于使用。
  6. Cygwin 下载完成后,点击“下一步”等完成安装,双击桌面上的 Cygwin 图标启动 Cygwin “命令提示符”。 您的主目录将自动设置在 Cygwin 文件夹中,现在应该在“C:\cygwin”中(Cygwin 文件夹在某种程度上就像您 Windows 机器上的一个小 Unix/Linux 计算机——当然不是技术上,但把它想象成那样可能会有所帮助)。
  7. 在 Cygwin 提示符下输入“g++”并按“回车”; 如果出现“g++: no input files”或类似的信息,则表示您已成功安装了 gcc C++ 编译器到您的计算机上(恭喜——您还刚刚收到您的第一个错误信息!)。

MinGW + DevCpp-IDE

  1. 前往 http://www.bloodshed.net/devcpp.html ,(严重过时,上次更新于 2005 年)(http://orwelldevcpp.blogspot.com/) (Updated Branch project) 选择您想要的版本(最终向下滚动),然后点击相应的下载链接! 对于最新版本,您将被重定向到 http://www.bloodshed.net/dev/devcpp.html
  2. 向下滚动以阅读许可证,然后到下载链接。 下载包含 Mingw/GCC 的版本。 它比自己组装要容易得多。 经过短暂的延迟(只有几天),您将始终获得与 devcpp IDE 打包的最新版本的 MinGW。 它与手动下载所需模块完全相同。
  3. 您将获得一个可执行文件,可以在任何 WinNT 版本的用户级别下执行。 但是,如果您希望将其设置为所有用户,则需要管理员权限。 它将安装 devcpp 和 mingw 到您想要的文件夹中。
  4. 启动 IDE 并体验您的第一个项目!
    您会发现它与 MSVC 大致相似,包括菜单和按钮放置。 当然,如果您熟悉前者,许多方面会有所不同,但只需点击几下即可让您的第一个程序运行。
对于 DOS
[编辑 | 编辑源代码]

DJGPP

  • 前往 Delorie 软件 并下载 GNU C++ 编译器和其他必要的工具。 该网站提供了一个 Zip Picker,以帮助您确定需要哪些文件,该文件可在主页面上获得。
  • 使用 unzip32 或其他提取工具将文件放置到您选择的目录中(例如 C:\DJGPP)。
  • 设置环境变量以配置 DJGPP 进行编译,方法是将行添加到 autoexec.bat 或自定义批处理文件中
    set PATH=C:\DJGPP\BIN;%PATH%
    set DJGPP=C:\DJGPP\DJGPP.ENV
  • 如果您运行的是 MS-DOS 或 Windows 3.1,则需要在 config.sys 中添加几行,如果它们不存在。
    shell=c:\dos\command.com c:\dos /e:2048 /p
    files=40
    fcbs=40,0

注意: DJGPP 下的 GNU C++ 编译器名为 gpp

对于 Linux
[编辑 | 编辑源代码]
  • 对于 Gentoo,GCC C++ 是系统核心的一部分(因为 Gentoo 中的所有内容都是编译的)
  • 对于 Redhat,获取一个 gcc-c++ RPM,例如使用 Rpmfind,然后使用以下命令安装(作为 root):rpm -ivh gcc-c++-version-release.arch.rpm
  • 对于 Fedora,使用以下命令安装 GCC C++ 编译器(作为 root):dnf install gcc-c++
  • 对于 Mandrake,使用以下命令安装 GCC C++ 编译器(作为 root):urpmi gcc-c++
  • 对于 Debian,使用以下命令安装 GCC C++ 编译器(作为 root):apt-get install g++
  • 对于 Ubuntu,使用以下命令安装 GCC C++ 编译器:sudo apt-get install g++
  • 对于 openSUSE,使用以下命令安装 GCC C++ 编译器(作为 root):zypper in gcc-c++
  • 如果您无法成为 root 用户,请从 [1] 获取 tarball 并按照其中的说明在您的主目录中编译和安装。
对于 Mac OS X
[编辑 | 编辑源代码]

Xcode(Apple 的 OSX 和 iOS 的 IDE)v4.1 以上版本使用 Clang [2],它是 GCC 编译器的免费开源替代方案,与 GCC 大致兼容(甚至使用相同的命令行参数)。 IDE 还捆绑了 GCC C++ 编译器的旧版本。 它可以通过与 Linux 相同的方式从终端调用,但也可以在 XCode 的其中一个项目中进行编译。

注意
Clang 不是 GCC 的唯一替代品,甚至不是唯一的免费替代品。 书籍的 外部链接部分 中包含了一些其他可能性。 Clang 已获得越来越多的采用,因为它允许更好的代码优化和内部索引,从而支持 IDE 中更复杂的功能,例如代码补全、高亮显示和其他程序员现在越来越依赖的现代功能。 这些在 GCC 上也是可能的,但需要构建和额外的工具,使其速度变慢。 虽然 GCC 仍然是免费开源 C++ 编译器的默认标准,但 Clang 似乎正在势头越来越大。 可用于 Linux(Ubuntu)、FreeBSD、OSX 和 Windows(mingw)的二进制文件可以从 https://llvm.net.cn/releases/download.html 下载。


Clipboard

待办事项
涵盖为什么要尽可能避免编译器扩展的章节(一页),并用于汇总 C++ 程序员应对编译器扩展所需的一些有用信息。

华夏公益教科书