一个程序员的一生
前言:
想起这个标题也是受到了 jyy 课程 https://jyywiki.cn/OS/2024/ 的影响,想要找到一个能将尽可能多的知识点全部串联起来的主题,就类似状态机,因此最终也是决定以这个为题。
之前也写过一点点点相关的内容,不过比较少。
这篇文章算是一篇对于操作系统知识(我个人了解的部分)的整理吧,可能会花费较多的时间去更新,因为我并不能保证所有涉及的知识点(或者说我想写的)我都已经很好的掌握了,所以这也算是一个查漏补缺的过程吧,希望我最终不会鸽掉它。
2024/08/03
诞生
今天是2024年9月的第一天,也是317灭亡的第一天,本想着来履行一个月前的承诺来写一点东西,却发现没有什么头绪,不过打都打开了,还是写一点吧。
大家都知道,一个 C++ 程序要经过四道工序才能变成一个可执行文件:
预处理 ---> 汇编 ---> 编译 ---> 链接
接下来就大致介绍一下每一个步骤的作用。
预处理
预处理可以使用 clang++ -E
(不出意外,后续都使用 clang 演示,不过这没啥大的区别)进行,在手册里是这么描述预处理的:
Preprocessing
This stage handles tokenization of the input source file, macro expansion, #include expansion and handling other prerprocessor directives. The output of this stage is typically called a ".i"(for C), ".ii"(for C++), ".mi"(for Objective-C), or ".mii"(for Objective-C++) file.
主要做的就是两件事:
- 展开所有的头文件、宏定义****,除了用户定义的宏以外,像
__LINE__
(输出当前行号)、__FILE__
(输出当前文件名)、__FUNCTION__
(输出当前函数名)之类的预定义的宏也会被一并展开。例如 GCC 的预定义宏可以在这里了解。 - 删除所有的注释,以及没有用到的
#ifdef
分支。 - 生成 linemarkers (TODO:这我也是第一次了解,需要补习)
注意这里的删除仅仅是用空行替代,所以程序的行数还是没有发生变化的。比如如下这么一个简单的程序,
#include <iostream>
#define PI 3.1415926
const int r = 2;
#define MAX(a, b) std::max((a), (b))
int main() {
#ifdef NOTEXIST
// Not exist
std::cout << (r * PI) << std::endl;
#else
// Exist
std::cout << (MAX(r, 1) * PI) << std::endl;
#endif
}
不考虑头文件,最后会得到
const int r = 2;
int main() {
std::cout << (MAX(r, 1) * PI) << std::endl;
}