知其然,知其所以然,进然能促学也。
参考资料
概述
什么是抽象机器(The Abstract Machine)
- “编程语言规范(不仅仅是C和C++,而是所有高级编程语言规范)根据抽象机器来定义语言,在这种用法中,抽象机器是能够用源语言(或一种语言家族,如JVM、.NET)执行程序的最简单的虚拟计算机” - Sergey Zubkow, www.quora.com (2015)
- C++抽象机是操作系统、内核和硬件的可移植抽象。- Bryce Adelstein Lelbach, Core C++ 2019
为什么需要抽象机器:
- 硬件太多了,甚至存在异构计算(CPU、GPU、嵌入式)。历史实践证明,不可能每个硬件采用不同的语言,这是低效的、不实际的;
- 让程序易读、让相关工具更方便制作。
C++ 的设计(关键)
设计目标:C++ 应该支持:
- 构建性能关键型软件(Performance-critical software):让程序员控制性能的各个方面;不给低级语言留下任何空间;
- 当前硬件架构、操作系统平台和环境的演变。
C++ 如何支持其设计目标的:
- C++ 和硬件之间没有任何抽象层或执行层。执行过程中没有抽象层:虽然编译器会生成汇编代码,但在实际运行时,C++程序是直接执行机器码的。这与其他高级语言不同,比如Python或Java,它们在运行时依赖于解释器或虚拟机来执行代码,形成了一种抽象层。
- C++ 将类型和操作直接映射到硬件上;
- 总的来说,C++ 定义了程序如何在一个被定义为“接近硬件”的抽象机器中工作。
图解抽象机器(从流程上理解)
运行示例
总结:当我们编写 C++ 代码时,我们是在面向 C++ 抽象机器写代码。
抽象机器的特征
Implementation 的含义(bob 总结,非 C++ 标准定义):在抽象机上验证程序并生成可执行映像的工具(编译器、链接器)。
注意1:存在未定义的操作。除了避免这类操作且将包含此操作的代码归类为非良构(ill-formed)外,C++ 标准没有给出任何要求。
注意2:在标准里,代码的副作用是被忽视的,标准假设所有 C++ 代码都没有产生副作用。副作用即代码运行上下文的改变。
未指明的行为(标准文件里未明确如何实现的行为 - Unspecified behavior)
每种未指明的行为都会产生来自有效结果集的任何可能的结果。 这是抽象机器中非确定性的一面。
交由实现来定义的行为例如:
- 函数调用中参数的求值顺序;
- 对于相同的字符串,程序是否需要明确地拷贝一份相同的值,亦或是指向同一个内存区域;
- 连续分配请求返回的存储顺序、连续性和初始值。
未定义行为(标准文件里没有要求的行为 - Undefined behavior)
对于这一类行为:
- 编译器没有被要求对这类行为做检测;
- 一个带有未定义行为的程序没有被要求具有任何意义。
这一类行为的示例:
- 对 nullptr 解引用;
- 访问数组访问范围外的内存;
- 有符号数溢出;
- 通过另一类型的指针访问某对象。
抽象机器的架构
内存部分
对象部分
总的来说,一个对象的生命周期和其存储周期几乎一致,其关系大致是。生命周期开始于初始化完成时,结束于析构函数被调用时。
线程部分
main() 函数与主线程
注意1:开始执行一个 C++ 程序时,会即刻开启调用 main() 函数的主线程。
注意2:静态存储期对象在调用 main() 之前初始化,并在退出 main() 后销毁。
线程与表达式
值类型参考:【240915】C++的值类型:lvalue, glvalue, xvalue, rvalue, prvalue