个人博客版:计算机初学知识图谱杂谈 | XavierSu知识馆 (learnya.cn)(可能刷新不出插图,就用上面的纯链接吧)
目录(点击跳转):
计算机必备原理计算机能做什么工作计算机是怎样工作的计算机内的数据保存:计算机内的二进制:数据保存:那么寄存器的是怎样存储数据的呢?在内存中,这些演算数据(程序运行)是怎样存储的呢?程序运行时内存的状态在硬盘中,这些习题(程序)是怎样存储的呢?与计算机通过“0”、“1”代码进行沟通计算机程序之编写到保存到运行的奇妙旅程(以C/C++为例子)最后说明(必读):当谈到学习C++编程的意义时,我想告诉后辈们的事:额外阅读:
看似很复杂的领域,实则确实很复杂
但是不用担心,我们生活中有很多例子可以帮助理解计算机的工作原理
一个复杂的事物出现,是由简单的事物一步步发展过来的
我们通过窥探该事物的发展过程和演变规律,有利于我们理解这一切
现在我并不想一开始就谈计算机的早期的发展历史,这些知识只要在网络上查询下,随处可见(1. 计算机早期历史-Early Computing_哔哩哔哩_bilibili),但是对于我们来说重要吗,重要,但不是非常重要,因为这并不影响我们去学习计算机的基础知识。如果面前的你立誓未来要成为计算机的专家,那这些发展历史还是很有必要学习的。
好了,下面开始
计算机必备原理
计算机能做什么工作
有趣生动形象的计算机工作原理科普先导短视频(双语推荐):计算机工作原理_哔哩哔哩_bilibili
所有计算机通常都要做4件事:输入、存储、运行、输出(下图英文)
计算机是怎样工作的
为了实现这四件事的功能,通常需要设计一套架构,
我们来聊的是最基础的版本,俗称冯诺依曼架构(三分钟带你了解冯.诺依曼结构 - 知乎 (zhihu.com))
冯.诺依曼确定了”计算机结构“中的5大部件:
- 运算器
- 控制器
- 存储器
- 输入设备
- 输出设备
笼统来说,上面五大部件,就是现在计算机的基础模型,现在我先不解释上述名词,我们来看个应用场景:
以点一杯奶茶为例:假设我们去奶茶店点一杯奶茶,流程是:
1.顾客告诉店员我们想要喝什么奶茶(口味、温度、甜度、配料等等)
2.店员用他们自己的话将我们的需求告诉奶茶制作人员
3.制作人员明白需求后着手开始制作奶茶(加什么料,加什么果酱,加多少糖等等)
4.制作人员将制作好的奶茶放到前台
5.店员打包递给等待的顾客,完成交易(省略付钱步骤)
场景对应:制作一杯奶茶
- 运算器: 就像奶茶店的制作人员一样,负责执行具体的制作动作。他计算着加入多少奶精,加入多少糖,搅拌多长时间等等。在手机里,这就是处理器,负责执行各种计算和操作。
- 控制器: 就像奶茶店的菜单一样,告诉运算器应该做什么。在这个例子里,它决定了制作的奶茶是珍珠奶茶还是绿茶奶茶。在手机里,这就是软件,比如你使用的聊天App、游戏或者浏览器,它们指导计算机做特定的事情。
- 存储器: 就像奶茶店的储存室一样,存储所有制作奶茶所需的材料,比如奶精、糖、茶叶等。在计算机里,这就是存储设备,比如内存和硬盘,用来存储你的照片、应用程序和文件。
- 输入设备: 就像客人告诉奶茶店老板他想要什么口味的奶茶一样,输入设备让我们能够把信息输入到计算机中。在手机中,触摸屏和键盘就是输入设备,它们让我们可以输入文字、触摸屏上的按钮等。
- 输出设备: 就像奶茶店的服务员把制作好的奶茶端给客人一样,输出设备把计算机处理后的信息呈现给我们。在手机里,屏幕和扬声器就是输出设备,它们显示文字、图片,播放音乐和视频等。
通过上述例子,可以发现,这套结构似乎能做的事情很多,毕竟生活中很多事情都可以这样来模拟,
那么对应到数学中,用来表示函数,就比较合适。一般的函数是f(x)=a+bx,初中阶段的f(x)应该称为y,即y=a+bx。我们可以看作x是输入,y是输出,那么a+bx就是运算过程,我们使用这个函数就是控制过程,保存这个函数就需要存储部件。
现在我们进行一层抽象,在编程中,比如在C++中最常见的函数:
例如:
我们把上述的函数y=a+bx在C++中写成计算过程(假如a=1,b=2):
(calculateY为函数命名方式,意为:计算y的值。在程序界,存在很多命名方式,根据情况使用)
上述函数提到了“类型——int”,在实际编程中,数据类型是多种多样的,目的是存储各种所需要的数据。如何理解呢,就比如买快递,不同的物品,快递会用不同的盒子包装甚至不是盒子包装(常规物品用纸盒子、水果蔬菜用泡沫箱、信件用信封等等)。在计算机数据中,这种存放数据的包装,就体现在数据类型上,短的数据用short、char,一般长度用int、float,更长数据用double,等等等等,还有更长的数据也有对应的包装,不过一般用的不多。
计算机内的数据保存:
在上面的解释中,为什么我把数据的属性用长度来称呼,要明白这一点,我们就要去了解数据在计算机中,是如何被保存的(类似于在一个快递货物中转的大仓库中,各种物品是如何被归类收纳存放的)。
计算机内的二进制:
解释上面的存储之前,还要提前讲一个“开关”的知识
在计算机中,我们常见“0”和“1”,”0“表示开关的开,”1“表示开关的关
众多科学家,在”0“和”1“的结合之中研究出了一整套计算机的科学,这是多么神奇的事啊。
上述的二进制,正好对应了开关的两种状态(”开“,”关“),这便是计算机计数的基础,也是计算机工作的”思考“方式。我们可以通过编写符合计算机语言语法规则的”0“、”1“组合,让计算机理解我们传递的意图。
接下来我先举个例子:
假设我有一台计算机,每次能理解连接的4个“单词”组成的一句话,这一个单词固定为8个”0“和”1“的组合。那么一句话就是8×4=32个”0“和”1“的组合(0000 0000 1111 1111 1010 1001 0000 0101)。
比如:(每个“单词”是通过掰计算机的8个开关来告诉计算机的。开关的红色表示”0“对应”开“状态,绿色表示”1“对应”关“状态,”问号“表示开关状态随便都行,这个开关可以忽略状态)
第一个单词:0000 0000、
第二个单词:1111 1111、
第三个单词:1010 1001 、
第四个单词:0000 0101、
那么由这四个“单词”组合的一句话就是:0000 0000 1111 1111 1010 1001 0000 0101
(这四个随便写的,没有具体意义。中间的空格是为了人一眼看见是32位,4位4位排一起)
阅读顺序:
我们规定从右到左为数数方式(和我们阅读习惯的从左往右的方式相反)
那么右边第一个开关状态为第1位(二进制的位=bit),
右边第二个开关状态为第2位,以此类推,那么右边第八个就是第8位,也就是左边第一个。
所以:
从右往左:第1位,第2位,第3位,第4位,第5位,第6位,第7位,第8位
从左往右:第8位,第7位,第6位,第5位,第4位,第3位,第2位,第1位
数据保存:
内存与硬盘的形象理解:
我们现在有了与计算机交流的“单词”,但是我们需要找个地方把这些话存储计算机的某个部件中,那这个部件就是内存和硬盘。
内存就像是我们考试做题的草稿纸,
硬盘就像是我们的习题册,
我们做题时,需要从习题册(硬盘)上读取题目
然后在草稿纸(内存)上进行演算,算完以后把结果写到习题册(硬盘)上,并把草稿纸(内存)上写的内容擦除以便后续再写。这个过程就类似计算机的软件程序运行的样子。
寄存器的形象理解:
寄存器是CPU中的部件,通常有很多个,它们就是程序运行时数据的快速存储位置(类似于我们做题时,临时记忆各种数据的我们的脑袋)
就像是我们在做习题时,虽然我们从习题册(硬盘)上将题目的过程在草稿纸(内存)上进行演算,但是演算过程中产生的各种数据和操作,大多是我们在大脑里心算完成的,然后再写到草稿纸上继续进行下一步骤。
所以,计算机的CPU需要寄存器来存储读取数据和操作指令。
那么寄存器的是怎样存储数据的呢?
类似于下图这个装8颗(现在的计算机64颗都有,这个8颗只是举例)巧克力的盒子,每一格装1位(1bit)数据,一盒装8位(8位=1字节,可以理解这个盒子就是1字节(1byte)),CPU中有很多这样的盒子,每个盒子都有对应的名字,目前我们暂且设计寄存器为0号到5号(一共6个寄存器,从0数到5)
在内存中,这些演算数据(程序运行)是怎样存储的呢?
首先我们用8位地址来表示1位数据的“0”或“1”的状态,8位地址的前4位表示列,后四位表示行,那么4位二进制可以表示十进制的0到15(从0开始数,有16个),
列×行=16×16=256,所以我们可以用8位地址找遍256个(0-255)表示“0”或“1”的1位(1bit)状态。
上图抽象一下,包装成这样的块:
但是我们用8位地址给出256处的某一处时,这个地方只有1位数据,我们如果需要同时读取8位及其以上的更多位不同的数据时该怎么办呢?
那么我们可以将8个256位的区域块(上图示例)连接在一起,使某8位的地址一起对应8个块(8位地址可以找寻某一块中256个地方),而这8个块里分别存不同的8位数据(对应0-8位的数据),如此一来,我们可以从256个不同地址中取出8位不同块中的数据用于组合成一字节(1byte=8bit)数据。
上图抽象一下:
这样,我们只需要给出某处的8位地址(0-255号),就可以得到这个地址中8位的数据。
在计算机系统中,有两种主要类型的地址:
- 逻辑地址:逻辑地址是程序中使用的地址,它是相对于程序的数据段或代码段等逻辑结构的偏移量。在程序中,我们使用的所有地址都是逻辑地址,包括全局变量的地址。逻辑地址是相对于程序的起始位置而言的。
- 物理地址:物理地址是内存条上的实际硬件地址,它表示计算机内存模块中的特定位置。
在运行时,操作系统的内存管理单元(Memory Management Unit,MMU)负责将逻辑地址映射到物理地址。这个映射过程通常涉及到分页、分段等技术,它使得程序可以在逻辑层面上使用大内存空间,而无需知道物理内存的实际结构。
程序运行时内存的状态
程序运行时(Linux系统)进行下的内存布局图:
上图的#1区域中,是按照 ELF 文件中的程序头信息,加载文件内容所得到的。然后加载器还会为每个程序进程分配栈区(Stack)、堆区(Heap)和动态链接库加载区。栈和堆分别向相对的方向增长,系统会有相应的保护措施,阻止越界行为发生。
当我们运行程序时,计算机里的操作系统会在内存中找些空的区域存放这个程序的关键信息和数据,并给这个程序的数据和运行安排布局
(类似于我们做题时将题目的要用的关键信息和数据写到草稿纸上,由于草稿纸上可能已经有地方再算其他题目,所以要找个空的区域来写这些信息和数据)
(也类似于我们想要吃一顿红烧排骨,从菜市场回来提了一大包各种蔬菜、排骨、调料,然后我们需要把这些食材按照厨房(内存)的布局,进行放置到特定的位置,已以进行做菜(运行)的准备)
布局中各处的解释:
在一个运行中的进程中,内存通常被划分为不同的段,每个段用于存储不同类型的数据和指令。以下是这些段的常见类型和意义:
- 代码段(Code Segment):
- 意义: 代码段存储程序的可执行指令。这些指令是程序的机器码表示,会被CPU执行。
- 访问权限: 通常是只读的,因为程序的代码在运行时不应该被修改。
- 只读数据段(Read-Only Data Segment):
- 意义: 存储不可修改的数据,例如常量、字符串文字等。
- 访问权限: 只读,确保数据的完整性。
- 读写数据段(Read-Write Data Segment):
- 意义: 存储程序运行时可能被修改的数据,例如全局变量等。
- 访问权限: 可读可写,程序可以读取和修改这里的数据。
- 堆(Heap):
- 意义: 堆是一块用于动态分配内存的区域。在堆上分配的内存由程序员手动分配和释放,通常用于存储动态创建的数据结构(例如链表、树等)和大型对象。
- 访问权限: 可读可写,程序员可以控制在堆上的数据的生命周期。
- 动态库加载区(Shared Libraries Area):
- 意义: 存储被多个程序共享的动态链接库(DLL、SO等)。这些库包含了多个程序可能会用到的函数和资源。
- 访问权限: 可读可执行,允许程序调用库中的函数。
- 栈(Stack):
- 意义: 栈用于存储函数调用时的局部变量、函数参数、返回地址等信息。每次函数调用都会在栈上创建一个新的帧。
- 访问权限: 可读可写,但通常只能在栈顶进行读写操作,以维护栈的结构。
- 内核地址空间(Kernel Address Space):
- 意义: 内核地址空间是操作系统内核的运行空间,存储操作系统的核心组件和数据。用户程序不能直接访问内核地址空间,它是受保护的区域。
- 访问权限: 通常只有操作系统内核有权限访问,用户程序无法直接访问内核地址空间。
这些内存段的划分和管理,使得操作系统能够有效地控制程序的访问权限,提高系统的安全性和稳定性。在程序执行时,这些内存段被操作系统管理和分配,确保不同的程序能够在内存中安全、有序地运行。
接下来使用C++编程,实现用某个地址装8位数据(0001 0001),然后再用指针(指向地址)从这个地址读出来里面装的数据(0001 0001):
程序运行结果:
这里我们可以看见,这个指针指向的地址里的数以二进制读出来就是0001 0001,十进制对应17。
该数据的地址(逻辑地址)为0000 7FF6 74C2 9004(位置在布局中的数据段中),当然这地址可太长了,远远不止到255号,这是因为我用的计算机是64位(16进制的1位表示二进制的4位,所以该逻辑地址是16×4=64位)的地址,而不是8位的,所以地址特别长。
而指针本本身的地址是0000 002F 67EF F738(位置在布局中的栈段中)。
该程序对应的布局解释:
binaryValue
(8位整数):- 数据:
binaryValue
被赋值为二进制数00010001
,表示为十进制是17
。 - 保存位置:
binaryValue
是一个全局变量,在程序运行时,它会被存储在数据段(Data Segment)中,通常位于可执行文件的数据区域。
- 指向
binaryValue
的指针ptr
: - 数据:
ptr
存储的是binaryValue
的内存地址。 - 保存位置:
ptr
变量本身(即指针变量)通常会被存储在栈(Stack)中。栈是一种用于存储局部变量和函数调用信息的内存区域。指针变量ptr
的值(即binaryValue
的地址)通常也是存储在栈中。
- 程序代码本身以二进制形式存放在代码段中
该程序出现的地址都是逻辑地址,虽然我这个逻辑地址很长,但是我内存中的实际物理地址没有这么长,操作系统的内存管理单元(Memory Management Unit,MMU)负责将逻辑地址映射到物理地址。所以我们在编程中主要关注逻辑地址就好,操作系统帮助我们自动转为物理地址和内存通信。
在硬盘中,这些习题(程序)是怎样存储的呢?
当我们谈论计算机的存储设备时,通常会提到两种主要类型:机械硬盘(HDD)和固态硬盘(SSD)。这两种硬盘在计算机中扮演着至关重要的角色,它们负责存储我们的操作系统、应用程序、文档和媒体文件等。
机械硬盘(HDD)包含有机械部件。它的内部有一个旋转的磁盘,数据存储在这个盘上。读取和写入数据时,磁头会在盘片上移动(有点像老式留声机和CD播放机),这个过程类似于一台精密的机械装置在工作。机械硬盘的优势在于它们相对便宜,而且容量很大,可以存储数TB(TB即千兆字节)的数据。且损坏后恢复数据比固态硬盘容易,数据安全性优于固态硬盘
固态硬盘(SSD) 则是一种不包含机械部件的存储设备。它的工作原理类似于您的闪存驱动器或内存卡。在固态硬盘内部,数据存储在闪存芯片上,这些芯片可以迅速读取和写入数据。相比之下,因为没有机械运动,固态硬盘的访问速度更快,响应更迅速。它们也更耐用,因为没有运动部件会因摩擦而磨损。
不论是HDD还是SSD,它们都遵循相同的数据传输协议,确保了它们可以轻松地与计算机的其他部件通信。在日常使用中,固态硬盘因其卓越的性能和快速的读写速度而备受青睐。它们使得计算机的启动速度更快,应用程序响应更迅速,同时也提供了更安静、更可靠的存储解决方案。
00:42时刻开始讲解硬盘之现代固态硬盘的工作原理【硬件科普】固态硬盘的缓存是干什么的?有缓存和无缓存有什么区别?_哔哩哔哩_bilibili
与计算机通过“0”、“1”代码进行沟通
接下来我们和计算机约定一下沟通的语法规则(指令集):
整体由4个段落(前面说的单词)组成,每个段落1字节(8位)
例如:0000 0000 1111 1111 0000 0000 1111 1111
(点击前面的小三角►进行打开或者折叠内容)
计算模式:
计算操作码 操作数1 操作数2 操作结果
在计算机指令集中,计算模式定义了指令的操作方式,使得计算机能够执行各种数学和逻辑运算。在计算模式中,指令由以下几个关键部分组成:
- 计算操作码: 计算操作码定义了具体的计算操作,例如加法、减法、乘法、逻辑与、逻辑或等。
- 操作数1 和 操作数2: 操作数1和操作数2是参与计算的数值,通常存储在寄存器中。这两个操作数被指令用于执行特定的计算操作。
- 操作结果: 操作结果是计算的输出,也通常存储在寄存器中,供后续的指令使用。
在计算模式中,可以通过修改计算操作码的类型,将操作数的位置从寄存器改变为立即数(8位最大表示为0到255的十进制数)。立即数是直接嵌入到指令中的数值,用于与操作数进行计算。
计算模式的语言(编码)规则:
计算操作码使用8位中的1、2、3、5、6、7、8位,
其中6、5位都为“0”则一起表示处于计算模式。(“0”=“开”=红色表示)
8、7位分别为“1”,“1”时,则表示将操作数1、2都从寄存器切换成立即数表示
8、7位分别为“1”,“0”时,则表示只将操作数1从寄存器切换成立即数表示
8、7位分别为“0”,“1”时,则表示只将操作数2从寄存器切换成立即数表示
3、2、1位一起表示具体那种计算模式(加减乘除逻辑运算)
加法模式:在处于计算模式(??00 ????)的情况下,当第3、2、1位都为0时
上图对应编码??00 ?000,表示计算模式的加法
减法模式:在处于计算模式(??00 ????)的情况下,当第3、2、1、位分别为0、0、1时
上图对应编码??00 ?001,表示计算模式的减法
我们规定了用于计算的操作码后,再规定操作数1,2对应的寄存器或者数值,就可以进行加减法运算了。
减法举例:
我们对应 [ 计算操作码 操作数1 操作数2 操作结果 ] 的语法规则(指令集),给计算机发送如下指令:
0000 0001 0000 0001 0000 0010 0000 0011
这就表示执行计算模式的减法模式(0000 0001 ),将1号(0000 0001 )寄存器里的数值减去2号(0000 0010 )寄存器里的数值,将结果存在3号(0000 0011)寄存器中。
立即数加法举例:1100 0001 0000 0001 0000 0010 0000 0011
将数值1(0000 0001 )和数值2(0000 0010 )相加,并将结果存放到3号(0000 0011)寄存器中。
(乘法或其他运算改3、2、1位的值,进行同理类推)…
条件模式:
条件操作码 判断数1 判断数2 跳转位置
条件模式用于控制程序的流程,根据条件的满足与否,使得程序可以选择性地执行不同的指令。在条件模式中,指令由以下几个关键部分组成:
- 条件操作码: 条件操作码定义了对两个判断数进行比较的条件,例如大于、小于、等于等。
- 判断数1 和 判断数2: 这两个判断数可以是寄存器中的值,也可以是立即数。条件操作码将这两个数进行比较,根据比较结果决定程序的跳转行为。
- 跳转位置: 跳转位置表示当条件成立时,程序将要跳转到的指令地址。
条件操作码使用1、2、3、5、6位,
其中6,5位分别为“1”、“0”则一起表示处于条件模式。(“1”=“关”=绿色表示)
在条件模式下,当第3、2、1位分别为1、0、0时,则表示大于模式
在条件模式下,当第3、2、1位分别为0、1、0时,则表示小于模式
在条件模式下,当第3、2、1位分别为0、0、0时,则表示等于模式
我们规定了用于条件判断的操作码后,再规定判断数1、判断数2的寄存器和跳转位置的内存地址,就可以进行条件操作了。
小于条件举例:
我们对应 [ 条件操作码 判断数1 判断数2 跳转位置 ] 的语法规则(指令集),给计算机发送如下指令:
0010 0010 0000 0001 0000 0010 0110 1011
这就表示执行小于模式(0010 0010 ),将1号(0000 0001)寄存器里面的数值和2号(0000 0010)寄存器里的数值进行比较,如果是1号小于2号,则将程序指令位置跳转到地址(0110 1011 )开始执行。
保存模式:
保存操作码 留空 数据位置 保存位置
保存模式用于将数据从一个位置保存到另一个位置,可以是从寄存器到内存、从内存到寄存器,或者其他存储设备。在保存模式中,指令由以下几个关键部分组成:
- 保存操作码: 保存操作码定义了具体的保存操作,例如将数据存储到内存、寄存器或外部设备。
- 留空: 此处可以留空或者包含一些附加信息,用于特定的指令标识或参数传递。
- 数据位置: 数据位置表示需要保存的数据源,可以是寄存器中的值、内存地址或其他数据来源。
- 保存位置: 保存位置指示了数据将要被存储的目的地,通常是寄存器、内存地址或外部设备。
保存操作码使用1、2、3、5、6位,
其中6,5位都为“1”则一起表示处于保存或者读取模式。(“1”=“关”=绿色表示)
在保存或者读取模式下,当第3、2、1位分别为0、0、1时,则表示保存模式
我们规定了用于保存的操作码后,再规定数据位置和保存位置的寄存器或内存地址,就可以进行读取操作了。
读取举例:
我们对应 [ 保存操作码 留空 数据位置 保存位置 ] 的语法规则(指令集),给计算机发送如下指令:
0011 0001 0000 0000 0000 0010 0110 1011
这就表示执行读取模式(0011 0000 ),将2号(0000 0010)寄存器里的数值保存到地址(0110 1011 )里。
读取模式:
读取操作码 留空 存储位置 读取位置
读取模式用于从指定位置获取数据,可以是从内存、寄存器或外部设备中读取数据。在读取模式中,指令由以下几个关键部分组成:
- 读取操作码: 读取操作码定义了具体的读取操作,例如从内存、寄存器或外部设备中获取数据。
- 留空: 此处可以留空或者包含一些附加信息,用于特定的指令标识或参数传递。
- 存储位置: 存储位置表示需要将读取的数据存储到的目的地,可以是寄存器、内存地址或其他数据存储位置。
- 读取位置: 读取位置指示了数据的来源,通常是内存地址、寄存器中的值或外部设备。
读取操作码使用1、2、3、5、6位,
其中6、5位都为“1”则一起表示处于保存或者读取模式。(“1”=“关”=绿色表示)
在保存或者读取模式下,当3、2、1位都为“0”则一起表示读取模式
我们规定了用于读取的操作码后,再规定存储位置和读取位置的寄存器或内存地址,就可以进行读取操作了。
读取举例:
我们对应 [ 读取操作码 留空 存储位置 读取位置 ] 的语法规则(指令集),给计算机发送如下指令:
0011 0000 0000 0000 0000 0010 0110 1011
这就表示执行读取模式(0011 0000 ),将地址(0110 1011 )里保存的数读取到2号(0000 0010)寄存器中。
以上指令集的设计使得计算机能够根据不同的需求,以不同的模式进行计算、逻辑判断、数据存储和读取,从而实现各种复杂的计算和逻辑操作。这种灵活性是现代计算机体系结构的重要特点之一,它使得计算机可以广泛应用于各种领域,满足不同应用场景的需求。
计算机程序之编写到保存到运行的奇妙旅程(以C/C++为例子)
——"程序童话:从代码的魔法到计算机的运行”
有了前面的知识储备,现在再来看这个程序运行的过程
童话讲解(看累了可以看这个):
编辑代码:
就像是写下了一篇魔法咒语,我们在编程软件工具(IDE)中
(比如vs studio、dev c++,clion),用无形的笔,编织着程序的魔法世界。
代码变成程序:
- 编译器的四大魔法流程:
- 预处理: 手指在键盘上跳舞,处理掉代码中的预处理指令,如宏定义和条件编译。
- 编译: 编译器是魔法师,将我们的代码翻译成机器能读懂的语言,即汇编语言。
- 汇编: 魔法文字化身成二进制代码,等待着被计算机读取。
- 链接: 魔法卷轴被卷成一卷,形成可执行文件,里面包含了程序的全部魔法秘密。
- PE/ELF文件:
- PE/ELF魔法书: 一个程序的所有魔法,被装进了一个神奇的魔法书,在Windows世界中叫做PE文件。在Linux世界中叫做ELF文件。
程序放在硬盘中:
硬盘图书馆: 在计算机的深海世界,程序魔法书躺在硬盘这座巨大的图书馆里,等待着被唤醒。
点击程序开始运行:
- 载入内存:
- 内存之梦: 程序被悄悄唤醒,飞入了内存的梦境。
- 内存布局:
- 内存乐园: 程序找到自己的一块小天地,开始在内存乐园里安家落户。
- 程序指令开始:
- 魔法指挥: CPU听到内存的呼唤,开始执行程序的魔法指令,程序从头到尾开始跳动。
- 内存到CPU:
- 内存传情: 内存和CPU开始互动,传递数据、条件和指令,编织出计算机的魔法交响乐。
- 数据计算、条件、读写运行:
- 魔法计算: CPU运行着魔法算法,数据在寄存器中舞蹈,条件被判断,读写操作在内存中穿梭,一切都像是在魔法王国里上演的盛大魔术表演。
... 直到关闭程序:
幕落: 当我们的魔法表演结束,程序从内存悄然消失,回到了硬盘的魔法图书馆,等待着下一次的魔法呼唤。
在计算机的世界里,代码是我们创造奇迹的魔法杖,程序则是这个奇迹的魔法世界。在每一次的点击和运行背后,都是程序员们的无限魔法创意!🎩🔮✨
正经讲解(很有精神可以看这个)
在程序的世界中,我们使用编程软件工具(IDE)(比如VS Studio、Dev C++、CLion)化繁为简,将想法写成代码。
代码变成程序:
- 编译器的四大流程:
- 预处理: 代码中的预处理器指令被执行,例如宏展开和文件包含。
- 编译: 源代码被编译成汇编语言。
- 汇编: 汇编语言被转换成机器码。
- 链接: 各个模块被链接成可执行文件。
- PE/ELF文件: 编译和链接后,程序被打包成PE(Portable Executable)和ELF(Executable and Linkable Format)是两种不同操作系统上的可执行文件格式,准备好在计算机上执行。在Windows中是PE文件。在Linux世界是ELF文件。
程序放在硬盘中:
PE/ELF文件被保存在硬盘上,等待被计算机读取运行。
点击程序开始运行:
当我们点击程序图标,程序开始运行。
操作系统为该程序开辟一个进程:
程序和进程有什么区别?
程序(或者狭义上讲可执行文件)是一个静态的概念,它就是一些预先编译好的指令和数据集合的一个文件;进程则是一个动态的概念,它是程序运行时的一个过程,很多时候把动态库叫做运行时( Runtime )也有一定的含义。
有人做过一个很有意思的比喻,说把程序和进程的概念跟做菜相比较的话,那么程序就是菜谱,计算机的CPU就是人,相关的厨具则是计算机的其他硬件,整个炒菜的过程就是一个进程。计算机按照程序的指示把输入数据加工成输出数据,就好像菜谱指导着人把原料做成美味可口的菜肴。
——摘自《程序员的自我修养—链接、装载与库》P150页的解释
- 载入内存: 程序从硬盘被加载到计算机的内存中,成为计算机的一部分。
- 内存布局: 内存被分成各个区域,包括代码段、数据段、栈和堆等。
- 程序指令开始: 计算机的CPU开始执行程序的指令,探索代码的奥秘。
- 内存到CPU: 数据和指令在内存和CPU之间穿梭,进行各种计算、判断、读写操作。
- 运行的过程显示在屏幕上: 程序的运行过程中,可能会产生各种输出,这些输出被显示在计算机屏幕上,向我们展示程序的执行情况。
- 数据计算、条件、读写运行: 程序开始运行,数据在内存和CPU之间跳舞,进行各种奇妙的计算和操作。
- 数据写回硬盘: 在程序执行过程中,可能会产生需要保存的数据。这些数据被写回硬盘,保留下程序的运行结果。
- 直到关闭程序: 程序持续运行,直到我们的任务完成,或者我们选择关闭它,结束这段神奇的旅程。
这就是一个程序的奇妙旅程,从代码的世界到计算机的现实,无处不充满了智慧的奥秘
最后说明(必读):
本文旨在以浅显易懂的方式介绍计算机硬件和指令集的基本知识。然而,作者的个人精力和知识储备有限,可能存在错误或不完整之处。读者在阅读本文时,应该保持批判性思维,对所学内容进行独立验证。
需要特别注意的是,文中所涉及的硬件知识和自定义指令集并不是现实世界某个具体产品的真实反映,它们只是基于经典模型原理的表示,用于帮助读者理解基本概念。
由于现实世界的技术产品不断迭代和升级,所以本文介绍的内容可能已经过时,不可直接套用在今天的具体产品上。
然而,尽管现代技术产品可能在细节上有所不同,但它们的基本原理仍然是经典的延伸。因此,本文的知识可以作为起点,启发读者深入学习,并在不同场景中融会贯通。我们鼓励读者在阅读本文的同时,积极参与讨论,指出错误和不足之处,以便我不断改进和提高文章的质量。
当谈到学习C++编程的意义时,我想告诉后辈们的事:
"孩子们,学习C++编程对你们来说意义非凡。这是一门有力的技能,它不仅仅是一门学科,更是一种思维方式。首先,它能够锻炼你们的逻辑思维和问题解决能力。编程是一门艺术,需要清晰的思维和耐心的思考,这些品质在生活中也同样重要。
其次,C++编程培养了你们的耐心和毅力。在编程的世界里,错误和挫折时常伴随而来。但是,每当你们克服一个难关,找到并解决了问题,那种成就感是无可比拟的。这种毅力和耐心将在未来的生活和工作中帮助你们不断前进。
此外,学习C++编程让你们提前了解了未来世界的一部分。在现代社会中,计算机技术已经无处不在。无论是在科研、工程、医学还是娱乐领域,编程都发挥着关键作用。学习C++编程为你们打开了一扇通向未来职业世界的大门。你们可以成为未来科技领域的创造者和引领者。
最重要的是,学习C++编程能够培养你们的团队协作和沟通能力。在一个编程项目中,很少有是一个人能够完成的。学会与他人合作、分享知识和经验,这将是你们未来职场成功的重要支持。
总之,学习C++编程不仅仅是学习一门技术,更是一种能力的培养和未来的投资。它将为你们的未来带来无限可能。加油吧,孩子们,掌握C++编程,你们将走向更广阔的未来之路!"
"孩子们,我明白学习C++可能会感到非常困难,但我想告诉你们,挑战是成长的过程。学好C++确实很有帮助,因为它是一门底层、强大且高效的编程语言,能够培养你们深入了解计算机内部工作原理的能力。现在有很多优秀的编程语言,C++是一个很好的起点,但它只是众多编程语言中的一个。每门语言都有自己独特的特点和擅长的领域,所以在选择主要语言时,需要根据个人兴趣和职业目标来做出明智的选择。
首先,让我们聊聊C++。C++是一门古老而强大的编程语言,它广泛用于游戏开发、系统编程、嵌入式系统等领域。如果你对计算机内部的工作原理和性能优化有兴趣,学习C++是个不错的选择。此外,C++的面向对象特性也为大型项目的开发提供了便利。
另外一门重要的语言是Java。Java是一门跨平台的编程语言,它被广泛应用于企业级应用、移动应用开发(Android平台)、大数据处理和云计算等领域。如果你对网络应用、移动应用或者大数据领域感兴趣,学习Java将会为你提供广泛的职业机会。
Python是一门简单易学的语言,它被称为“人工智能时代的胶水语言”。Python在数据科学、人工智能、机器学习、Web开发等领域非常流行。如果你对人工智能、数据分析或者科学计算有兴趣,学习Python将会事半功倍。
当然,还有其他语言如JavaScript、C#、Ruby等,它们都有各自的特点和应用领域。在选择主要语言时,你们可以考虑以下几个因素:
- 兴趣: 选择你感兴趣的领域和项目,然后选择与之相匹配的语言。
- 就业前景: 研究一下你所在地区或者你希望就业的领域,哪些语言在招聘市场上需求较大。目前不考虑就业可以暂时忽略这条。
- 学习难度: 不同的语言有不同的难度,根据自己的学习能力和时间安排选择适合的语言。
- 未来发展: 考虑一下各门语言的未来发展趋势,选择一个具有长期发展前景的语言。
最重要的是,不要局限于一门语言。学习一门编程语言后,掌握编程的基本思维方式后,学习其他语言将变得更加容易。多门语言的掌握将使你们在未来的职业生涯中更具竞争力。无论选择哪门语言,坚持学下去,勤奋实践,将会为你们的未来打下坚实的基础。加油,孩子们,未来的编程世界等着你们去探索!"
感谢阅读,希望有所帮助
目前字数:11757字
额外阅读:
C++有趣的知识点初学C++编程时,以下几个方面是需要特别注意的:
- 基础语法和语义: 确保你对C++的基本语法、数据类型、控制结构(如循环和条件语句)和函数的定义与调用等有清晰的了解。建议从最简单的程序开始,逐步增加复杂度。
- 面向对象编程(OOP): C++是一种面向对象的编程语言,因此要深入理解类、对象、继承、多态和封装等概念。这些是C++中非常重要的概念,也是编写复杂程序的基础。
- 内存管理: 在C++中,你需要手动分配和释放内存。了解new和delete关键字的使用,以及智能指针(如std::shared_ptr和std::unique_ptr)的概念,可以帮助你避免内存泄漏和野指针问题。
- STL(标准模板库): 熟悉STL中的常用数据结构(如向量、队列、映射等)和算法(如排序、查找等)。STL提供了很多现成的工具,可以大大简化你的编程工作。
- 异常处理: 了解C++的异常处理机制,学会使用try、catch和throw关键字来处理异常,提高程序的健壮性。
- 代码组织和规范: 学会良好的代码组织和命名规范,这样可以使你的代码更易读、易懂,也更容易与他人合作。
- 实践和项目经验: 编写小型项目或参与开源项目,实践是学习编程最好的方式。通过实际项目,你能够应用所学知识,锻炼解决问题的能力。
- 阅读他人代码: 阅读别人的开源项目或者高质量的C++代码可以帮你学习到一些优秀的编程实践和设计模式。
- 版本控制: 学习使用版本控制系统(如Git),它能够帮助你管理代码的版本,方便团队协作和追踪代码变更。
- 持续学习: C++是一门广泛且深入的编程语言,持续学习新的特性、最佳实践和设计模式,能够使你在C++编程中保持竞争力。
记住,编程是一门实践性很强的技能,多动手写代码,多实践,将理论知识应用到实际问题中,是掌握C++编程的关键。
【【百万好评】国外大神!!油管千万级收藏,C++技术大佬带你从入门到精通,新手快速进阶!全中文字幕,学不会我退出IT界-哔哩哔哩】 https://b23.tv/795eSZr