一切的开始:一段编程完成的C++代码
从IDE中编写完成的代码,实质是还只是一串字符串,当然也可以看成一个CPP后缀的文件,里面放着字符串。
这段代码,是需要根据约定去编写的,这种约定便是语言的规则,各种约定会伴随着这段程序的诞生到销毁。
第一个约定:编程语法
我们在C++中编写的程序,需要遵循他自己的一套语法,这种语法一般体现了语言的特点,诸如是否对缩减敏感(PYTHON),垃圾回收(JAVA),一个语句结束的标志是什么(C++是“;”),关键字,语言是否简洁、紧凑,使用方便、灵活,是否拥有丰富的运算符等等。
第二个约定:编译器的分析(词法/语法/语义)
在我们完成与语言语法的约定后,语言也会和我们的编译器来形成约定,来告诉编译器该如何将这些语言转换为语法树,进而转换为中间码。
每一个语言的转换步骤都不尽相同,因为对一个语句而言,可以有很多种的解释方法,也就是很多种的分析方法。
举个简单的例子:
约定 INT X1 = X2;
表示将X1的值付给X2(其两者的数据类型都需要是INT),语句的结束由“;”符号标识。
根据这段约定,便会产生一个专属于这个语言的语法树,从而利用这个语法树产生中间码。
PS:其实一个语句完成不成体系,能理解便好 : )
注:在此处C++会将库,头文件,内联函数,宏等完成处理
第三个约定:CPU与中间码
编译器在完成了与语言的约定后,便会进行到这个步骤,这个步骤是因为市面上会存在很多的CPU类型(主要是指令集的不同和位数的不同:64/32)
编译器需要将中间码根据不同的CPU来进行特定的转换,从而得到最终的机器码。
这种约定体现在汇编语言的之上:
汇编语言是用人类看得懂的语言来描述指令集,不同的CPU支持的指令大不相同,所以不同CPU的汇编语言便会产出不同,无法统一进行翻译。
这时候便需要CPU与中间码的约定,来保证这种翻译过程中不会产生错误,这样编译器便可以根据不同的CPU来产生不同的汇编语言了。
现在我们的字符串程序已经根据不同的CPU的不同来翻译为特定的汇编语言了,也就是说,我们得到了目标代码,不过这种代码不一定是可运行的,比如C++,这时候便需要进行链接,将库与依赖导入,这种导入可以将库与依赖的目标代码导入已有的目标代码中。
注:如果目标代码是汇编指令代码,则需汇编器汇编之后才行运行。
好了,我们已经拥有可以运行的目标代码了,就只剩下运行了。
第四个约定:程序与操作系统
这里,我们的程序在准备开始运行时的前提会产生分歧:
一种是在小型的,嵌入式的CPU上执行的程序,小而精,没有操作系统。
一种是在个人主机(此处不考虑分布式,超大型主机)上运行程序,拥有操作系统。
有无操作系统,程序在执行过程中的很多操作都会有不同:
内存管理:在操作系统下,程序需要经过内存管理单元的管理,才能使用内存资源。在没有操作系统的情况下,程序需要自己管理内存,手动分配和释放内存空间。
外设访问:在操作系统下,程序需要通过操作系统提供的API接口来访问外设资源,如磁盘、网络等。在没有操作系统的情况下,程序需要自己编写底层驱动程序,直接访问硬件资源。
进程管理:在操作系统下,程序运行在进程的上下文中,由操作系统进行调度和管理。在没有操作系统的情况下,程序需要自己管理进程,包括创建、调度、销毁等操作。
其他还有多线程(没有操作系统,便不会有上下文切换的代价),安全性等问题。
如此,程序在执行过程中,也会有不同的,需要遵循的约定,主要在操作系统上:
上下文切换(用户态与内核态之间的互相转换)
进程的阻塞(单核的,简单的CPU不会产生这种问题)
进程管理(时间片轮转,先来先服务,最短作业优先,优先级)
CPU调度(先来先服务,最高响应比优先,时间片轮转)
进程管理主要涉及进程的创建、撤销、阻塞、唤醒、同步和通信等方面。
CPU调度是对CPU资源的管理过程,主要涉及对进程调度和切换的控制和管理。
两者十分相似,区别在于,进程管理是对进程的管理和控制,而CPU调度是对CPU资源的管理和调度。进程管理是CPU调度的基础,CPU调度是进程管理的延伸。二者之间的关系是相互依存的。
注:这个部分对于“约定”表述的不是很清晰,有点抽象,个人水平有限。
计算机:约定组成的网络
计算机是依靠一系列的约定和规则,使得软硬件能够协同工作,完成各种复杂的任务。这些约定和规则是不断发展和完善的,它们不是死板的,而是随着技术的进步和应用场景的变化而不断演化。进程管理和CPU调度是操作系统的两个重要组成部分,它们共同协作,以实现程序运行的效率最大化。
C++作为一门高级编程语言,屏蔽了汇编语言的复杂性,让开发人员能够更加专注于业务逻辑的实现。因此,了解计算机体系结构和编程规则,能够帮助我们更好地理解软硬件协同工作的原理,为编写高质量的程序提供帮助。
注:如有错误,请指正,谢谢。