C++
计算机科学导论
探索计算机思维,像计算机一样思考,并开始整理你的思维过程。
更系统地思考,更有方法地解决问题,最终将这些转化为代码。
对很多人来说,编程确实是其中的一个重要部分,因为通过编写代码,你可以表达想法,解决实际问题,特别是涉及数据的问题。但计算机科学本身其实就是一门研究信息的学科。
你如何表现信息,又如何实际处理信息?计算思维就是将计算机科学中的思想,例如像这门课程中学到的内容,应用到你感兴趣的东西。
抽象
从技术上讲,抽象是一个在计算机科学中随处可见的术语,而实际上,问题解决也是如此。
抽象就是指简化某些东西,使你不必关注低层次的实现细节。你只需关注高层次的目标或过程本身。
“抽象” 我听过很多次了,不真正了解或关心发动机的工作原理和所有运动部件。它是一种抽象,但有机械师,了解这些更低级别的实现细节。
如果每次你想去学校或去商店都必须理解汽车是如何工作的,那可能会变得相当慢。
你只是希望在更高级别的抽象层次上思考和操作,我们在编写代码和解决问题时将一直这样做。
“抽象” 一般来说,计算机科学家会称之为算法,即解决某个问题的分布指令。
C++
人类程序员编写的代码,被称为源代码。
源代码是作为人类程序员,最终要编写的内容的总称。
当然,实际上计算机并不理解源代码。
计算机本身并不理解 C 语言代码。它们只懂 0,1这是二进制,但实际上,它是用二进制表示的信息。
用专业术语说,这是 “0” 和 “1” 的模式,计算机不仅能将其解释为字母,数字,颜色,图像等
它还能够执行,因此从现在开始,这种模式将被称为机器码,以与源代码形成对比。
所以,虽然我们这些人类编写源代码,但计算机最终只能理解机器码。
我们需要中间的一些东西来将源代码转换为机器代码。
编译器
编译器是一个将一种语言翻译成另一种语言的程序。
为什么我们想要直接访问硬件,你用 C++ 写的代码,这些代码被送去编译器去编译这些编译器将代码输出为目标平台的机器码,机器码是你的设备在 CPU 上实际执行的指令,使用 C++ 我们完全可以控制 CPU 执行的每一条指令。
C++ 是本地语言,C++编译器为目标平台和目标架构生成机器码,就这样了。
#include <iostream>
int main()
{
std::cout << "hello wordl" << std::endl;
std::cin.get();
}
预处理
在#符号之后的都是预处理语句
编译器收到源文件后,一看到这条语句就先处理这些个预处理语句
这就是为什么叫 预处理了,因为它在实际编译发生之前就被处理了。
include 的含义是它需要找到一个文件,在这个例子中,需要找到叫 iostream 的文件
然后讲该文件所有内容拷贝到现在的文件内,这些你所包含的文件通常被成为 “头文件”
我们之所以要包含 iostream 这个头文件是因为我们需要一个被调用的函数的声明:std::cout
可以让我们在终端打印东西。
main 函数非常重要,因为任何一个 C++程序都有 main函数
main函数是程序的入口,意思当我们运行程序时,计算机就从这个函数开始执行代码
当程序还在运行时,计算机会琢行执行我们的代码。
当然,程序也可以中断或者改变执行的顺序,他们是控制语句或者是函数调用,但最主要的还是一行
一行的执行,因此,我们的程序首选被执行的是 cout helloworld 这句然后是 cin.get 这句
了解函数的人会发现,main 函数的返回是 int 类型,然而,我们并没有返回 int,这是因为 main 函数比较特殊,它不一定需要返回值。
main 函数比较特殊,它不一定需要返回值。main 函数的返回是 int 类型,然后,我们并没有返回 int ,这是因为 main 函数比较特殊,它不一定需要返回值,如果你不返回值的话,它会默认你返回了 0,这个只对 main 函数适用是一种特殊情况
#include <iostream>
int main()
{
std::cout << "hello wordl" << std::endl;
std::cin.get();
}
<< 这个箭头符号看上去很奇怪,其实他们只是写成这个样子,并没有更多的实际含义,这些看上去像左移运算符的东西叫做重载运算符你可以把它理解为一个函数
endl 告诉终端跳到下一行
cin.get函数是等待我们按下 enter 键在前往下一句代码之前等待,这个时候程序暂停执行。
直到我们按下回车键后,程序继续运行下一行,但已经没有下一行了,所以程序返回 0.意味着代码执行完了。
main.cpp,我们怎么把它转换成可运行的二进制文件?这有几个步骤
首选我们已经 include iostream 这是预处理语句。
编译器先处理这些语句,在这个例子中,编译器会将 iostream 文件内容全部包含进来。
当预处理语句处理完了之后,我们的文件将被编译。这个阶段,编译器将所有 C++ 代码转化为实际机器代码,这里有些非常重要的设置决定我们怎么转化代码。
简单的函数
#include <iostream>
void log(const char *message)
{
std::cout << message << std::endl;
}
int main()
{
log("hello word");
// std::cout << "hello world" << std::endl;
// 等待用户输入,防止程序立即退出
std::cin.get();
return 0;
}
C++ 编译器如何工作
编译器实际上需要做的唯一一件事,将我们的文本文件拿来,转换他们,转换成一种成为目标文件的中间格式。
首先,它需要预处理我们的代码,这意味着所有的预处理语句都会先处理,一旦我们的代码被预处理,接下来我们将或多或少地进行记号化和解析,基本上把这个 C++ 语言整理成编译器能够真正理解和推理的格式。
这基本上导致了所谓的抽象语法树被创建,它基本上是我们代码的一种表示,但是抽象的语法树。
编译器每天的工作是转换我们所有的代码转换成常量数据或指令。一旦编译器创建了这个抽象语法树,它可以开始实际生成代码。这段代码就是实际的机器,我们 CPU 将执行的代码,我们还得到了其他各种数据,比如一个存储所有常量,变量的地方,这基本上就是编译器所做的一切。这并不复杂。
编译器所做的就是生成 obj文件为每个我们的 C++ 文件,现在,我们的项目包含的每个 CPP 文件告诉编译器。这些 CPP 文件被称为翻译单元。
本质上,你必须意识到 C++ 不关心文件,文件不是存在于 C++ 中的东西。
比如,在 Java中,类名必须是和你的文件名称一样,你的文件夹层次,需要和package一样,因为这是 Java 的要求。
C++ 没有所谓的文件,文件只是提供给编译器源代码的一种方式,你负责告诉编译器你输入的是什么类型的文件以及编译器应该如何处理它。我可以制作 .cherno 文件,只要我告诉编译器这个文件是一个 C++ 文件请像编译 C++文件一样编译它,请记住文件没有意义。
编译器将把文件变成一个翻译单元,翻译单元会生成一个 obj 文件,实际上,有时在 CPP 文件中包含其他的 CPP 文件,变成一个大的 CPP 文件,是很常见的。
编译的第一阶段
在预处理阶段的处理,编译器基本上会遍历我们所有的预处理语句并对其进行处理,我们常用的预处理语句是 include if ifef,还有 pragma语句。
常用的预处理器语句 #include,它指定了你想要包含的文件,预处理器打开那个文件,阅读它的所有内容。然后把它粘贴到你写调度文件中,就是这样。
C++ 链接
链接是一个过程,当我们从源 C++ 文件转到实际的可执行工作,二进制文件。
第一阶段是 编译源文件,一旦我们把文件编译好,我们需要通过一个叫做链接的过程,现在链接的主要焦点是找到每个符号和函数在哪里并把它们连接起来。
记住每个文件被编译成一个单独的目标文件,一个翻译单元,它们彼此之间没有关系,这些文件不能交换,所以如果我们决定把我们的程序分割成多个 C++ 文件,这当然很常见,我们需要一种方法把这些文件连接在一起成一个项目,而这就是链接器的主要目的和要做的事情。即使你在外部文件中没有函数。
我用 vs-code 写,超级麻烦,链接不起作用。我觉得我现在也接触不到需要那种格式化,或者说工程化吧。