000 compilers

这篇文章主要是关于compilers的基本概念,从c++编程语言学习的角度。

compilers

计算机只能理解一种语言,而这种语言由一组由 1 和 0 组成的指令组成。这种计算机语言被恰当地称为机器语言。对计算机的一条指令可能如下所示:

00000 10011110

如果你想计算两个数字的总和,作为机器语言程序可能指令长这样:

00000 10011110
00001 11110100
00010 10011110
00011 11010100
00100 10111111
00101 00000000

因此,还是得搞点高级语言,毕竟代码是死的,人是活的,活人就会犯错。哪个更容易检查,书写,看懂 别人的代码 显而易见。如下所示的c++代码和上面的机器语言干的活一样:

int a, b, sum;
     
cin >> a;
cin >> b;
             
sum = a + b;
cout << sum << endl;

什么是complier?

人说人话高级语言,机器只听机器语言,各种compilers, interpreters, assemblers 干的事情就是当翻译。

compiler interpreter assembler
把高级语言转成机器语言,一次性全转 把高级语言转成机器语言,一行一行的转 把汇编语言转成机器语言
C ,C++ Ruby,Perl,Python,PHP 汇编语言

C++被设计成一种编译型语言,也就是说c++代码一般被翻译成系统可以直接理解的机器语言,使得生成的程序非常高效。为此,需要一组工具,称为开发工具链(development toolchain),其核心是编译器(complier)及其链接器(linker)。

开发工具链

chatGPT解释开发工具链:

开发工具链(development toolchain)是一组工具和软件的集合,用于编写、编译、调试和部署软件应用程序。对于C++这样的编译型语言,开发工具链尤为重要,因为它们负责将人类可读的源代码转换为计算机可执行的机器语言。下面是开发工具链的主要组成部分:

  1. 文本编辑器:开发工具链的起点通常是文本编辑器,程序员用它来编写源代码。常见的文本编辑器包括Visual Studio Code、Sublime Text、Atom等。
  2. 编译器(Compiler):编译器是开发工具链的核心部分,负责将高级语言(如C++)编写的源代码转换为机器语言。对于C++,常见的编译器包括GNU Compiler Collection(GCC)、Clang等。编译器将源代码文件编译成目标文件(object files),这些文件包含机器代码的二进制表示。
  3. 链接器(Linker):链接器将编译器生成的目标文件以及任何必要的库文件连接在一起,创建一个可执行的程序。它负责解决外部符号引用、符号重定位等问题。在C++开发中,链接器起到了很重要的作用,尤其是在引入外部库、静态库和动态链接库时。常见的链接器包括GNU ld、Microsoft Link等。
  4. 调试器(Debugger):调试器是开发过程中的关键工具,用于诊断和修复代码中的错误(bug)。它允许开发人员逐行执行代码、查看变量的值以及跟踪程序执行过程。常见的调试器包括GDB、LLDB、Visual Studio Debugger等。
  5. 构建工具(Build Tools):构建工具用于自动化和管理项目的构建过程。它们可以处理依赖关系、编译源代码、链接目标文件,并执行其他必要的任务,以确保项目的正确构建。在C++开发中,常用的构建工具包括Make、CMake、Bazel等。
  6. 性能分析工具(Performance Profilers):性能分析工具帮助开发人员评估程序的性能并识别性能瓶颈。它们可以提供关于CPU使用情况、内存分配情况和函数调用频率等信息。常见的性能分析工具包括Valgrind、gprof、Intel VTune等。

以上是开发工具链中的一些关键组件,它们共同构成了一个完整的开发环境,使程序员能够高效地开发、调试和优化C++应用程序。

已经有点看得云里雾里了,但是没关系。工具链 = 干活全家桶 ,这样是不是非常的好归类。

window下c++

red panda dev c++是一款国人开发的IDE(Integrated Development Environment,IDE),可以理解成上面1-6的全家桶软件放到一个软件里。

但是都是全家桶套餐,肯德基和麦当劳都能吃饱,但里面侧重什么还是有些不同的。👉 不同的IDE对于C++的特性会选择程序不同的部分进行实现,编译器是比较关键的区别。

dev-c++(red panda dev c++的参考软件,但是后面没继续开发了):MinGW or TDM-GCC 作为底层编译器。

这一点在运行下方代码的时候:

  1. 保存文件到D:/libregd/c++/test.cpp,test.cpp 是文件的名字,test就是测试的意思,.cpp就是一种格式,类似word大多都叫XXXX.docx
#include <iostream>
using namespace std;
int main()
{
	string x;
  	cin >> x;
  	cout << x;
}
  1. 运行(run)

tools output 得到下方的内容,()内的内容是自己添加的

- Filename: D:/libregd/c++/test.cpp (*a.)
- Compiler Set Name: MinGW GCC 11.2.0 64-bit Debug (*b.)

Processing C++ source file: (*c.)
------------------
C++ Compiler: D:/libregd/RedPanda-Cpp/MinGW64/bin/g++.exe (*d.)
Command: g++.exe  "D:/libregd/c++/test.cpp" -o "D:/libregd/c++/test.exe" -g3 -pipe -Wall -Wextra (*e.运行了一条命令)

Compile Result:(*f. )
------------------
- Errors: 0  (*g. )
- Warnings: 0 (*h. )
- Output Filename: D:/libregd/c++/test.exe (*i. )
- Output Size: 166.63 KiB (*j. )
- Compilation Time: 0.374 secs (*k. )

让我们开始做一些整理:

*编号 含义
a. 文件名字不仅有文件名字,还有文件名字所处的位置
b. 编译器也有名字
c. 开始编译了
d. 编译器的地址和程序名字
e. 运行了一条命令
f. 结果,有结果说明运行成功了
g. 说明是0错误,自动帮你检查的,基于别的程序员们写好的检查规则
h. 警告0,原理同上
i. 输出了一个文件, test.exe ,和.cpp 同名,但格式不同了
j. test.exe 的文件大小
k. 编译过程的使用时间,0.374秒

里面其实已经涵盖了很多内容了,只是乍一看感觉啥也没说。

文件路径为什么有的/有的\

Q:D:/libregd/c++ ? 我在windows下的文件不都是D:\libregd\c++这样吗?(说着打开一个文件管理器,查看路路径)

A:这是一个历史遗留问题,就像手机是安卓还是苹果一样,这里说明g++.exe还是以linux的标准来做事,针对windows做了一些小小的内部一键转换。

总结

越是靠近现代的编程生态软件,越使用linux的标准。

g++ 在windows下怎么用的?

Q: Command: g++.exe "D:/libregd/c++/test.cpp" -o "D:/libregd/c++/test.exe" -g3 -pipe -Wall -Wextra 这条命令怎么理解?

A:chatGPT:

这个命令是使用GNU编译器(g++)将一个名为 "test.cpp" 的源代码文件编译成一个可执行文件,并指定输出文件名为 "test.exe"。下面是对命令中各部分的解释:

  • g++.exe: 这是GNU编译器的可执行文件。在Windows系统中,".exe" 扩展名表示可执行文件。
  • "D:/libregd/c++/test.cpp": 这是待编译的源代码文件的路径。在这个例子中,源代码文件名为 "test.cpp",位于 "D:/libregd/c++/" 目录下。路径被双引号括起来,是因为路径中包含了空格,这样可以确保路径被正确解析。
  • -o "D:/libregd/c++/test.exe": 这是指定编译器生成的可执行文件的输出路径和名称。在这个例子中,可执行文件将被命名为 "test.exe" 并保存在 "D:/libregd/c++/" 目录下。同样地,路径被双引号括起来。
  • -g3: 这是一个编译选项,表示生成调试信息。"-g" 选项后面的数字表示调试信息的详细程度,这里的 "3" 表示生成最详细的调试信息,有助于在调试器中进行精确的源代码级别调试。
  • -pipe: 这是一个编译选项,告诉编译器在编译过程中使用管道来加速编译。
  • -Wall: 这是一个编译选项,表示开启所有警告信息。编译器将尽可能地检测代码中潜在的问题,并给出警告信息。
  • -Wextra: 这是一个编译选项,表示开启额外的警告信息。它会启用一些额外的警告,帮助开发者捕捉更多潜在的问题。

这个命令会将 "test.cpp" 编译成一个带有调试信息的可执行文件,并将其命名为 "test.exe",保存在指定路径下。

Q:显而易见这是在windows下的command ,在linux下这个命令会是如何呢?

chatGPT:

在Linux下,相同的命令也可以使用,只是路径分隔符和可执行文件的扩展名会有所不同。下面是相同的命令在Linux下的写法:

g++ "D:/libregd/c++/test.cpp" -o "D:/libregd/c++/test" -g3 -pipe -Wall -Wextra

在Linux下的主要区别有:

  • 路径分隔符不同:Linux下使用的路径分隔符是斜杠(/),而不是Windows下的反斜杠(\)。
  • 可执行文件没有扩展名:在Linux下,可执行文件通常不包含扩展名,所以输出文件名只是 "test",而不是 "test.exe"。

其余部分的命令格式和含义与在Windows下是相同的。

总结

看来自由度还是自己终端运行command的好。

计算机的存储容量都有哪些?

Q: Output Size: 166.63 KiB ,看起来KiB 是一种单位?能帮我科普相关的常识吗?用词简洁精要,有表格的话更好。

当谈论计算机存储容量时,常用的单位包括字节(Byte)、千字节(Kilobyte,KB)、兆字节(Megabyte,MB)、吉字节(Gigabyte,GB)等。而KiB则是其中的一种更精确的单位,表示“二进制千字节”(Kibibyte)。

下面是常见存储容量单位的表格:

单位 简称 等于
字节 B 1字节
千字节 KB 1,000字节 (10^3)
兆字节 MB 1,000,000字节 (10^6)
吉字节 GB 1,000,000,000字节 (10^9)
TiB TB 1,000,000,000,000字节 (10^12)
PiB PB 1,000,000,000,000,000字节 (10^15)
EiB EB 1,000,000,000,000,000,000字节 (10^18)
ZiB ZB 1,000,000,000,000,000,000,000字节 (10^21)
YiB YB 1,000,000,000,000,000,000,000,000字节 (10^24)

KiB(Kibibyte)与KB(Kilobyte)的区别在于,KB是指1000字节,而KiB是指1024字节。在计算机领域,通常会使用二进制单位(如KiB、MiB、GiB等)来更精确地表示存储容量,特别是在涉及到计算机内存、硬盘容量等方面。

总结

这么看Kib更符合计算机的规则了,但日常大家也就是KB啥的用一用,比较方便,符合直觉,现实生活也是10进制的嘛。

编译时间都花哪里去了

Q:Compilation Time: 0.374 secs 这个时间很短,而且我想知道过程到底干了啥?

A: chatGPT 给出的建议是需要考虑使用命令,也就是MINGW64

你可以使用命令行工具来查看编译器的详细输出,其中可能包含编译时间的信息。具体的命令取决于你所使用的编译器。

在你的情况下,你使用的是g++编译器,你可以通过在命令行中添加 -ftime-report 选项来生成编译时间的报告。这个选项会显示编译过程中各个阶段所花费的时间。

例如,你可以这样使用命令进行编译:(test1.cpp 和上面test.cpp内容完全一样)

g++.exe test1.cpp -o test1.exe -ftime-report

编译完成后,编译器会输出详细的编译时间报告,其中包含了每个阶段的耗时信息,你可以从中找到编译过程所用的时间。

采用这个办法确实生成得到了一个新的test1.exe,而且通过在命令行里 ./test1.exe,可以运行

下面则是-ftime-report给出的内容:

| Phase                           | Time (wall) | Time (%) | Memory (sys) | Memory (%) |
|--------------------------------|-------------|----------|--------------|------------|
| Phase setup                    | 0.00        | 1%       | 1582k        | 4%         |
| Phase parsing                  | 0.21        | 86%      | 37M          | 86%        |
| Phase lang. deferred           | 0.02        | 9%       | 4042k        | 9%         |
| Phase opt and generate         | 0.01        | 4%       | 402k         | 1%         |
| Name lookup                    | 0.03        | 12%      | 1663k        | 4%         |
| Overload resolution            | 0.02        | 10%      | 2906k        | 7%         |
| Preprocessing                  | 0.04        | 17%      | 1796k        | 4%         |
| Parser (global)                | 0.04        | 15%      | 14M          | 34%        |
| Parser struct body             | 0.04        | 16%      | 6858k        | 16%        |
| Parser function body           | 0.01        | 6%       | 2362k        | 5%         |
| Parser inl. func. body         | 0.01        | 6%       | 1421k        | 3%         |
| Parser inl. meth. body         | 0.02        | 7%       | 2867k        | 6%         |
| Template instantiation         | 0.07        | 29%      | 11M          | 27%        |
| TOTAL                          | 0.24        | -        | 43M          | -          |

总结

phase parsing 对于这段代码来说,时间花最多。

g++ 指定不同参数 会导致 exe文件大小区别?

通过同样的内容的cpp文件编译的,只不过一个在redpanda dev 里,一个在MINGW64 命令行里:

test.exe 167kb
test1.exe 130kb

我想知道这种区别如何导致的,结论是-g 具有很大的影响。

名称 使用的编译参数(前面都是 g++ test1.cpp -o testX.exe) 大小(kb)
test1.exe -ftime-report 130
test2.exe -ftime-report -finput-charset=UTF-8 -fexec-charset=gbk -g3 -pipe -Wall -Wextra 251
test3.exe -ftime-report -g3 -pipe -Wall -Wextra 251
test4.exe -ftime-report -g3 -pipe -Wall 251
test5.exe -ftime-report -g3 -pipe 251
test6.exe -ftime-report -g3 251
test7.exe -ftime-report -g2 178
test8.exe -ftime-report -g1 133

chatGPT:

-g 参数是用来生成调试信息的,它会将调试符号包含在可执行文件中,以便在调试程序时使用。因此,加入 -g 参数会增加可执行文件的大小。

在你的第一条命令中,你没有加入 -g 参数,因此编译器并没有生成调试信息,所以可执行文件的大小相对较小。

而在第二条命令中,你加入了 -g3 参数,它会生成更多的调试信息,因此可执行文件的大小会更大。通常,较大的调试信息对于深度调试来说很有用,但是在生产环境中,你可能会想要将这些信息删除以减小可执行文件的大小。

所以,如果你不需要进行深度调试,可以省略 -g 参数,以减小可执行文件的大小。

总结

高手用终端干活也不是没有道理,不过普通环境估计还是找个趁手的IDE就行了,初学者,我感觉啥都能凑活上。

在线Web IDE

也许windows 还是有些局限,可以使用在线的网站作为学习c++的入门来用:cpp.sh

这个网站提供了c++98,c++11,c++14,c++17,c++20,c++23作为可选的运行标准

也可以尝试根据关键词在线c++ 获得一些别的更适合的在线可以运行c++代码的网站,比如发现了一篇几款优秀的支持C、C++在线编译器

什么叫standard(标准)?

就像iPhone 4 一路到iphone15一样,语言本身是动态发展的,就像2000年以前“牛逼”也不是一个夸人的词。

c++ 本身作为一门语言也是不断发展的。98,11,20,23,这些数字指代的是年份,那一年推出的新标准。

本笔记采用c++11作为学习的环境是因为参考的教程内容也是11年的。

参考引用