《程序是怎样跑起来的》--享受方便同时了解原理

前言:我们在享受这些方便的同时也付出了代价。虽然拥有一定的编程能力,却无法进一步提高自身技能;知识应用能力的不足导致无法编写源程序。越来越多的程序员正为这些问题而烦恼。个中原因在于,大家不了解程序运行的根本机制。“双击程序图标,程序开始运行”,作为一名程序员,对程序的了解仅仅停留在这一表层是不行的。我们还应该了解更深层的机制:加载到内存中的机器语言程序,由CPU进行解析和运行,进而计算机系统整体的控制和数据运算也开始运行。了解了程序的运行机制后,就能找到编写源程序的方法。

本书由浅入深,对于了解计算机底层有很大帮助。包括cpu,控制硬件,应用,操作系统,二进制,文件压缩,内存和磁盘,编译器等。

第一章CPU

补充:

内存包括寄存器、缓存和主存。外存有光盘、U盘、软盘、磁带等。CPU的寄存器有多个类型,有的可以运算,有的可以存放一些数据。Cache缓存是为了提高CPU和主存之间传输数据的速度 。主存常用于存储活动状态的程序和数据。

计算机硬件由CPU,内存,硬盘,外设组成。CPU由寄存器,运算器,控制器和时钟组成。程序的运算和执行是由CPU来负责,程序员编写的高级程序语言经过编译器编译后转为CPU能够识别的机器语言。寄存器分为程序计数器,基址寄存器,变址寄存器,通用寄存器,累加计数器,标志寄存器和栈。数组由基址寄存器保留数值,由变址寄存器保留索引。函数的运行通过call指令将上一步放入栈,执行完成后用return指令将栈中保留的执行下一步命令调用出来。机器语言指令其实非常少,有运算指令,数据转送指令,跳转指令和call/return指令。

通常所说的内存指的是计算机的主存储器(main memory),简称主存。主存通过控制芯片等与CPU相连,主要负责存储指令和数据。主存由可读写的元素构成,每个字节(1字节=8位)都带有一个地址编号。CPU可以通过该地址读取主存中的指令和数据,当然也可以写入数据。但有一点需要注意,主存中存储的指令和数据会随着计算机的关机而自动清除。


《程序是怎样跑起来的》--享受方便同时了解原理_第1张图片
《程序是怎样跑起来的》--享受方便同时了解原理_第2张图片
《程序是怎样跑起来的》--享受方便同时了解原理_第3张图片

第二章二进制

想必大家都知道计算机内部是由IC这种电子部件构成的。第1章介绍的CPU(微处理器)和内存也是IC的一种。IC有几种不同的形状,有的像一条黑色蜈蚣,在其两侧有数个乃至数百个引脚;有的则像插花用的针盘,引脚在IC内部并排排列着。IC的所有引脚,只有直流电压0V或5V两个状态。也就是说,IC的一个引脚,只能表示两个状态。

IC的这个特性,决定了计算机的信息数据只能用二进制数来处理。由于1位(一个引脚)只能表示两个状态,所以二进制的计数方式就变成了0、1、10、11、100…这种形式。

位是最小单位,字节是基本单位。内存和磁盘都使用字节单位来存储和读写数据,使用位单位则无法读写数据。因此,字节是信息的基本单位。

10的零次幂和10的一次幂等称作位权,10称为基数。十进制基数是10,二进制基数是2

十进制数左移后会变成原来的10倍、100倍、1000倍……同样,二进制数左移后就会变成原来的2倍、4倍、8倍……反之,二进制数右移后则会变成原来的1/2、1/4、1/8……这样一来,大家应该能够理解为什么移位运算能代替乘法运算和除法运算了吧。

二进制数中表示负数值时,一般会把最高位作为符号来使用,因此我们把这个最高位称为符号位。符号位是0时表示正数,符号位是1时表示负数。

补数就是用正数来表示负数,很不可思议吧。

为了获得补数,我们需要将二进制数的各数位的数值全部取反,然后再将结果加1。例如,用8位二进制数表示- 1时,只需求得1,也就是00000001的补数即可。具体来说,就是将各数位的0取反成1, 1取反成0,然后再将取反的结果加1,最后就转化成了11111111

出现了最高位溢出的情况,不过,正如之前所介绍的那样,对于溢出的位,计算机会直接忽略掉。在8位的范围内进行计算时,100000000这个9位二进制数就会被认为是00000000这一8位二进制数

补数求解的变换方法就是“取反+ 1”。牢记“将二进制数的值取反后加1的结果,和原来的值相加,结果为0”这一法则

右移有移位后在最高位补0和补1两种情况。当二进制数的值表示图形模式而非数值时,移位后需要在最高位补0。类似于霓虹灯往右滚动的效果。这就称为逻辑右移


《程序是怎样跑起来的》--享受方便同时了解原理_第4张图片
《程序是怎样跑起来的》--享受方便同时了解原理_第5张图片

将二进制数作为带符号的数值进行运算时,移位后要在最高位填充移位前符号位的值(0或1)。这就称为算术右移。如果数值是用补数表示的负数值,那么右移后在空出来的最高位补1,就可以正确地实现1/2、1/4、1/8等的数值运算。如果是正数,只需在最高位补0即可。

只有在右移时才必须区分逻辑位移和算术位移。左移时,无论是图形模式(逻辑左移)还是相乘运算(算术左移),都只需在空出来的低位补0即可。

计算机能处理的运算,大体可分为算术运算和逻辑运算。算术运算是指加减乘除四则运算。逻辑运算是指对二进制数各数字位的0和1分别进行处理的运算,包括逻辑非(NOT运算)、逻辑与(AND运算)、逻辑或(OR运算)和逻辑异或(XOR运算)四种。

“逻辑非是所有位的取反操作”“逻辑与是将一部分变为0(复位到0)的操作”“逻辑或是将一部分变为1(复位到1)的操作”“逻辑异或是将一部分进行取反(相同取0,不同取1)的操作”

第四章内存

内存实际上是一种名为内存IC的电子元件。虽然内存IC包括DRAM、SRAM、ROM等多种形式,但从外部来看,其基本机制都是一样的。内存IC中有电源、地址信号、数据信号、控制信号等用于输入输出的大量引脚(IC的引脚),通过为其指定地址(address),来进行数据的读写。


《程序是怎样跑起来的》--享受方便同时了解原理_第6张图片

这个内存IC中能存储多少数据呢?数据信号引脚有D0~D7共八个,表示一次可以输入输出8位(=1字节)的数据。此外,地址信号引脚有A0~A9共十个,表示可以指定0000000000~1111111111共1024个地址。而地址用来表示数据的存储场所,因此我们可以得出这个内存IC中可以存储1024个1字节的数据。因为1024=1K,所以该内存IC的容量就是1KB。

通常情况下,计算机使用的内存IC中会有更多的地址信号引脚,这样就能在一个内存IC中存储数十兆字节的数据。因此,只用数个内存IC,就可以达到512MB的容量。

首先,我们假设要往该内存IC中写入1字节的数据。为了实现该目的,可以给VCC接入+5V,给GND接入0V的电源,并使用A0~A9的地址信号来指定数据的存储场所,然后再把数据的值输入给D0~D7的数据信号,并把WR(write=写入的简写)信号设定成1。执行完这些操作,就可以在内存IC内部写入数据


《程序是怎样跑起来的》--享受方便同时了解原理_第7张图片

编程语言中的数据类型表示存储的是何种类型的数据。从内存来看,就是占用的内存大小(占有的楼层数)的意思。即使是物理上以1个字节为单位来逐一读写数据的内存,在程序中,通过指定其类型(变量的数据类型等),也能实现以特定字节数为单位来进行读写。

通过使用变量,即便不指定物理地址,也可以在程序中对内存进行读写。这是因为,在程序运行时,Windows等操作系统会自动决定变量的物理地址。

指针也是一种变量,它所表示的不是数据的值,而是存储着数据的内存的地址。通过使用指针,就可以对任意指定地址的数据进行读写。

数组是指多个同样数据类型的数据在内存中连续排列的形式。作为数组元素的各个数据会通过连续的编号被区分开来,这个编号称为索引(index)。指定索引后,就可以对该索引所对应地址的内存进行读写操作。而索引和内存地址的变换工作则是由编译器自动实现的。


《程序是怎样跑起来的》--享受方便同时了解原理_第8张图片
《程序是怎样跑起来的》--享受方便同时了解原理_第9张图片
《程序是怎样跑起来的》--享受方便同时了解原理_第10张图片
《程序是怎样跑起来的》--享受方便同时了解原理_第11张图片

在需要追加或删除数据的情况下,使用链表是很高效的。使用链表方式处理数组的好处就是性能更好,移动的元素比单纯处理数组少


《程序是怎样跑起来的》--享受方便同时了解原理_第12张图片
《程序是怎样跑起来的》--享受方便同时了解原理_第13张图片

二叉查找树是指在链表的基础上往数组中追加元素时,考虑到数据的大小关系,将其分成左右两个方向的表现形式。例如,假设我们事先把50这个值保存到了数组中。那么,如果接下来的值比先前保存的数值大的话,就要将其放到右边,反之如果小的话就放在左边。但实际的内存并不会分成两个方向,这是在程序逻辑上实现的

使用二叉查找树的便利之处在于可以使数据的搜索等更有效率。在使用一般的数组时,必须从数组的开头按照索引顺序来查找目标数据。而使用二叉查找树时,当目标数据比现在读出来的数据小时就可以转到左侧,反之目标数据较大时即可转到链表的右侧,这样就加快了找到目标数据的速度。

第五章磁盘


通过使用内存来提高磁盘访问速度的机制称为什么?磁盘缓存,将需要的数据从磁盘取出存储在内存,下次需要直接在内存中高速读出。

借助虚拟内存,哪怕是内存容量不足的计算机,也可以运行很大的程序。

扇区是磁盘保存数据的物理单位。

从都具有存储程序命令和数据这点来看,内存和磁盘的功能是相同的。在计算机的5大部件中,内存和磁盘也都被归类为存储部件。不过,利用电流来实现存储的内存,同利用磁效应来实现存储的磁盘,还是有差异的。而从存储容量来看,内存是高速高价,而磁盘则是低速廉价。

大家平时使用的计算机,至少都配备了512M大小的内存和80GB大小的磁盘。在计算机这个系统中,高速小容量的内存与低速高容量的磁盘进行协同作业。内存主要是指主内存(负责存储CPU中运行的程序指令和数据的内存),磁盘主要是指硬盘。

计算机的五大部件包括输入装置(键盘、扫码器、语音话筒等等)、输出装置(显示屏、语音听筒等等)、存储器(磁盘、内存等等)、运算器(CPU的运算寄存器)、控制器(CPU的控制器)。

CPU只能执行加载到内存中的程序。虚拟内存虽说是把磁盘作为内存的一部分来使用,但实际上正在运行的程序部分,在这个时间点上是必须存在在内存中的。也就是说,为了实现虚拟内存,就必须把实际内存(也可称为物理内存)的内容,和磁盘上的虚拟内存的内容进行部分置换(swap),并同时运行程序。

为了实现虚拟内存功能,Windows在磁盘上提供了虚拟内存用的文件(page file,页文件)。该文件由Windows自动做成和管理。文件的大小也就是虚拟内存的大小,通常是实际内存的相同程度至两倍程度。通过Windows的控制面板,可以查看或变更当前虚拟内存的设定。

由于使用虚拟内存时发生的Page In和Page Out往往伴随着低速的磁盘访问,因此在这个过程中应用的运行会变得迟钝起来。想必大家也都有过在操作应用的过程中硬盘访问灯一直亮着(这时正在进行Page In和Page Out),导致应用一时无法操作的不愉快经历吧。也就是说,虚拟内存无法彻底解决内存不足的问题。

提高运行效率方法:

(1)通过DLL文件实现函数共有

DLL(Dynamic Link Library)文件,顾名思义,是在程序运行时可以动态加载Library(函数和数据的集合)的文件。此外,还有一个需要大家注意的地方,那就是多个应用可以共有同一个DLL文件。而通过共有同一个DLL文件则可以达到节约内存的效果。

第六章文件压缩

文件是字节数据的集合体。

jpeg是图片的压缩方式之一


《程序是怎样跑起来的》--享受方便同时了解原理_第14张图片
《程序是怎样跑起来的》--享受方便同时了解原理_第15张图片

把文件内容用“数据×重复次数”的形式来表示的压缩方法称为RLE(Run Length Encoding,行程长度编码)算法

RLE算法经常被用于传真FAX等。G3类传真机是把文字和图形都作为黑白图像来发送的。由于黑白图像的数据中,白或黑通常是部分连续的,因此就没有必要再发送这部分数据的值(白或者黑),而只需附带上重复次数即可,这样压缩效率就得到了大幅提升。例如,像白色部分重复5次,黑色部分重复7次,白色部分重复4次,黑色部分重复6次这样的部分图像,就可以用5746这样的重复次数数字来进行压缩。

哈夫曼树:


图像文件并不要求还原到压缩前的质量,但是可执行文件和一些文本文件每一个字符和数值都有具体意义,需要能够还原到压缩前状态。称为不可逆压缩和可逆压缩。


《程序是怎样跑起来的》--享受方便同时了解原理_第16张图片

原始的图像文件是BMP格式。通过此图可以看出,JPEG格式和GIF格式的图像文件有一些模糊。这是因为JPEG格式的文件是非可逆压缩,因此还原后的图像信息有一部分是模糊的。而GIF格式的文件虽然是可逆压缩,但因为有色数不能超过256色的限制,所以还原后颜色信息会有一些缺失,进而导致了图像模糊。TIFF格式的图像文件虽然不模糊,但却比原始的BMP格式的文件还要大,这是为什么呢?我们知道,TIFF格式的文件中带有各种标签信息,是可以选择压缩格式的,而这里选择的是与BMP同样的无压缩方式。但由于与原始的图像数据相比,TIFF格式的文件中附加了标签信息,所以结果就比BMP格式的文件更大了。

第七章运行环境

运行环境=操作系统 + 硬件

AT兼容机:

指的是可以和IBM开发的pc/at在硬件上相互兼容的计算机

CPU只能解释其自身固有的机器语言。不同的CPU能解释的机器语言的种类也是不同的

机器语言的程序称为本地代码(native code)。程序员用C语言等编写的程序,在编写阶段仅仅是文本文件。文本文件(排除文字编码的问题)在任何环境下都能显示和编辑。我们称之为源代码。通过对源代码进行编译,就可以得到本地代码。在市面上出售的用于Windows的应用软件包CD-ROM中,收录的就不是源代码,而是本地代码


《程序是怎样跑起来的》--享受方便同时了解原理_第17张图片

API也称为“系统调用”,是应用调用操作系统功能的手段。应用程序向操作系统传递指令的途径称为API(Application Programming Interface)

像键盘输入、鼠标输入、显示器输出、文件输入输出等同外围设备进行输入输出操作的功能,都是通过API提供的。

在同类型操作系统下,不管硬件如何,API基本上没有差别。因而,针对某特定操作系统的API所编写的程序,在任何硬件上都可以运行。当然,由于CPU种类不同,机器语言也不相同,因此本地代码当然也是不同的。这种情况下,就需要利用能够生成各CPU专用的本地代码的编译器,来对源代码进行重新编译了。

提供不依赖硬件和操作系统的程序运行环境方法三种,虚拟机,ports移植和JAVA虚拟机

大家说的Java,有两个层面的意思。一个是作为编程语言的Java,另一个是作为程序运行环境的Java。

引导程序是存储在启动驱动器起始区域的小程序。

开机后,BIOS会确认硬件是否正常运行,没有问题的话就会启动引导程序。引导程序的功能是把在硬盘等记录的OS加载到内存中运行。虽然启动应用是OS的功能,但OS并不能自己启动自己,而是通过引导程序来启动。

第八章从源文件到可执行文件

将多个目标文件结合生成EXE文件的工具称为什么?链接器,所以只运行一个EXE文件即可启动。

通过对源文件进行编译,得到目标文件。例如,C语言中,将Sample1.c这个源文件编译后,就会得到Sample1.obj这个目标文件。目标文件的内容是本地代码。

链接器会从库文件中抽取出必要的目标文件并将其结合到EXE文件中。此外,还存在一种程序运行时结合的DLL形式的库文件。

把导入库信息结合到EXE文件中,这样程序在运行时就可以利用DLL内的函数了。

编译器首先读入代码的内容,然后再把源代码转换成本地代码。编译器中就好像有一个源代码同本地代码的对应表。但实际上,仅仅靠对应表是无法生成本地代码的。读入的源代码还要经过语法解析、句法解析、语义解析等,才能生成本地代码。根据CPU类型的不同,本地代码的类型也不同。因而,编译器不仅和编程语言的种类有关,和CPU的类型也是相关的。

现在编译器基本上不需要购买,都已经默认集成到开发IDE中了。

把多个目标文件结合,生成1个EXE文件的处理就是链接,运行连接的程序就称为链接器(linkage editor或连结器)。Borland C++的链接器就是ilink32.exe的命令行工具。在Windows命令提示符下运行以下命令后,程序所需的目标文件就会被全部链接生成Sample1.exe这个EXE文件。

程序:(配合下面的图)

link32 -Tpe -c -x -aa c0w32.obj Sample1.obj, Sample1.exe, ,        import32.lib cw32.lib

链接选项“-Tpe-c-x-aa”是指定生成Windows用的EXE文件的选项。在这些选项之后,会指定结合的目标文件。而该命令行中就指定了c0w32.obj、Sample1.obj这两个目标文件,这点相信大家都能看得出来。Sample1.obj是Sample1.c编译后得到的目标文件。c0w32.obj这个目标文件记述的是同所有程序起始位置相结合的处理内容,称为程序的启动。因而,即使程序不调用其他目标文件的函数,也必须要进行链接,并和启动结合起来。

像import32.lib及cw32.lib这样的文件称为库文件。库文件指的是把多个目标文件集成保存到一个文件中的形式。链接器指定库文件后,就会从中把需要的目标文件抽取出来,并同其他目标文件结合生成EXE文件。

sprintf()等函数,不是通过源代码形式而是通过库文件形式和编译器一起提供的。这样的函数称为标准函数。之所以使用库文件,是为了简化为链接器的参数指定多个目标文件这一过程。

Windows中,API的目标文件,并不是存储在通常的库文件中,而是存储在名为DLL(Dynamic Link Library)文件的特殊库文件中。就如Dynamic这一名称所表示的那样,DLL文件是程序运行时动态结合的文件。在前面的介绍中,我们提到MessageBox()的目标文件是存储在import32.lib中的。实际上,import32.lib中仅仅存储着两个信息,一是MessageBox()在user32.dll这个DLL文件中,另一个是存储着DLL文件的文件夹信息,MessageBox()的目标文件的实体实际上并不存在。我们把类似于import32.lib这样的库文件称为导入库。

与此相反,存储着目标文件的实体,并直接和EXE文件结合的库文件形式称为静态链接库。静态(static=静态的)同动态(dynamic=动态的)是相反的意思。存储着sprintf()的目标文件的cw32lib就是静态链接库。sprintf()提供了通过指定格式把数值转换成字符串的功能。(对上面一大段总结:也就是标准函数这些Windows的API一开始是保存在dll文件内,当开始链接时就将需要用到的标准函数导入到lib文件,这个导入过程叫做导入库。不知道理解是否准确)


《程序是怎样跑起来的》--享受方便同时了解原理_第18张图片

总结一下Windows中的编译及链接机制总结一下Windows中的编译及链接机制:结合上面的程序代码得出的结论应该是,源代码编译后的目标文件,加启动用的目标文件,加静态链接库文件里面需要的函数,加导入库文件,导入库里面有调用动态链接里面的函数信息,最后生成可执行文件。

程序加载时会生成栈和堆。EXE文件的内容分为再配置信息、变量组和函数组,这一点想必大家都清楚了吧。不过,当程序加载到内存后,除此之外还会额外生成两个组,那就是栈和堆。栈是用来存储函数内部临时使用的变量(局部变量),以及函数调用时所用的参数的内存区域。堆是用来存储程序运行时的任意数据及对象的内存领域

加载到内存的程序由4部分构成:


《程序是怎样跑起来的》--享受方便同时了解原理_第19张图片

栈及堆的相似之处在于,他们的内存空间都是在程序运行时得到申请分配的。不过,在内存的使用方法上,二者存在些许不同。栈中对数据进行存储和舍弃(清理处理)的代码,是由编译器自动生成的,因此不需要程序员的参与。使用栈的数据的内存空间,每当函数被调用时都会得到申请分配,并在函数处理完毕后自动释放。与此相对,堆的内存空间,则要根据程序员编写的程序,来明确进行申请分配或释放。

第九章操作系统和应用的关系

相同整合为操作系统,独立不同称为应用。

程序员是通过利用操作系统提供的功能来编写应用的。

在计算机中尚不存在操作系统的年代,完全没有任何程序,因此程序员就需要编写出处理相关的所有程序。用机器语言编写程序,然后再使用开关将程序输入,这一过程非常麻烦。于是,有人开发出了仅具有加载和运行功能的监控程序,这就是操作系统的原型。

操作系统是多个程序的集合体,硬件和软件处理方面兼顾。操作系统的诞生使得程序员不用继续编写控制硬件的程序,也减少编写一些基础的程序。

要想成为一个全面的程序员,有一点需要清楚的是,掌握基本的硬件知识,并借助操作系统进行抽象化,可以大大提高编程效率。否则,遇到问题时,你就无法找到解决办法。操作系统确实为程序员提供了很多方便。不过,仅仅享受方便是不行的,还要了解为什么自己能够这么方便。了解了这一点,就可以尽情地享受方便了。

应用程序不是面向硬件而是面向操作系统,操作系统收到指令后再控制硬件


《程序是怎样跑起来的》--享受方便同时了解原理_第20张图片

操作系统的硬件控制功能,通常是通过一些小的函数集合体的形式来提供的。这些函数及调用函数的行为统称为系统调用(system call),也就是应用对操作系统(system)的功能进行调用(call)的意思。

C语言等高级编程语言并不依存于特定的操作系统。这是因为人们希望不管是Windows还是Linux,都能使用几乎相同的源代码。因此,高级编程语言的机制就是,使用独自的函数名,然后再在编译时将其转换成相应操作系统的系统调用(也有可能是多个系统调用的组合)。也就是说,用高级编程语言编写的应用在编译后,就转换成了利用系统调用的本地代码


《程序是怎样跑起来的》--享受方便同时了解原理_第21张图片

程序员没必要写直接控制硬件的代码,因为操作系统和高级程序语言将硬件抽象化了。比如一个磁盘的存储区抽象为文件。

多任务指的是同时运行多个程序的功能。Windows是通过时钟分割技术来实现多任务功能的。

即插即用:新的设备连接到计算机后,系统就会自动安装和设定用来控制该设备的设备驱动程序。

Windows中,网络功能是作为标准功能提供的。数据库(数据库服务器)功能有时也会在之后进行追加。网络功能和数据库功能,虽并不是操作系统本身不可欠缺的功能,但因为它们和操作系统很接近,所以被统称为中间件而不是应用。意思是处于操作系统和应用的中间(middle)。操作系统和中间件合在一起,也称为系统软件。应用不仅可以利用操作系统,也可以利用中间件的功能

程序是操作系统、中间件、应用等所有软件的统称。因此,通常程序员制作的应该都是应用,而不是操作系统。不过,既然是应用,那么就肯定会通过某种形式来利用操作系统的功能。

第十章汇编语言

例如,在加法运算的本地代码中加上add(addition的缩写)、在比较运算的本地代码中加上cmp(compare的缩写)等。这些缩写称为助记符,使用助记符的编程语言称为汇编语言。

汇编语言指令的语法结构是操作码+操作数(也存在只有操作码没有操作数的指令)。在汇编语言中,类似于mov这样的指令称为“操作码”(opcode),作为指令对象的内存地址及寄存器称为“操作数”(operand)。

现在基本上没有人用汇编语言来编写程序了。因为C语言等高级编程语言用1行就可以完成的处理,使用汇编语言的话有时就需要多行,效率很低。不过,汇编语言的经验还是很重要的。因为借助汇编语言,我们可以更好地了解计算机的机制。特别是对专业程序员来说,至少要有一次使用汇编语言的经验

“线程”是操作系统分配给CPU的最小运行单位。源代码的一个函数就相当于一个线程。多线程处理指的是在一个程序中同时运行多个函数的意思。

第十一章硬件控制方法

控制CPU,只需把编译器或汇编器生成的本地代码加载到主内存并运行就可以了。那么,如何用程序来控制CPU和主内存以外的硬件呢?

Windows直接控制了作为硬件的显示器。但Windows本身也是软件,由此可见,Windows应该向CPU传递了某些指令,从而通过软件控制了硬件。

Window控制硬件时借助的是输入输出指令。其中具有代表性的两个输入输出指令就是IN和OUT。这些指令也是汇编语言的助记符。IN指令通过指定端口号的端口输入数据,并将其存储在CPU内部的寄存器中。OUT指令则是把CPU寄存器中存储的数据,输出到指定端口号的端口。

计算机主机中,附带了用来连接显示器及键盘等外围设备的连接器。而各连接器的内部,都连接有用来交换计算机主机同外围设备之间电流特性的IC。这些IC,统称为I/O 控制器。由于电压不同,数字信号及模拟信号的电流特性也不同,计算机主机和外围设备是无法直接连接的。为了解决这个问题,I/O控制器就很有必要了。

I/O是Input/Output的缩写。显示器、键盘等外围设备都有各自专用的I/O控制器。I/O控制器中有用于临时保存输入输出数据的内存。这个内存就是端口计算机主机中,附带了用来连接显示器及键盘等外围设备的连接器。而各连接器的内部,都连接有用来交换计算机主机同外围设备之间电流特性的IC。这些IC,统称为I/O 控制器。由于电压不同,数字信号及模拟信号的电流特性也不同,计算机主机和外围设备是无法直接连接的。为了解决这个问题,I/O控制器就很有必要了。

I/O是Input/Output的缩写。显示器、键盘等外围设备都有各自专用的I/O控制器。I/O控制器中有用于临时保存输入输出数据的内存。这个内存就是端口。CPU内部的寄存器是用来进行数据运算处理的,而I/O寄存器则主要是用来临时存储数据的。

一个I/O控制器既可以控制一个外围设备,也可以控制多个外围设备。各端口之间通过端口号进行区分。端口号也称为I/O地址。

以端口为桥梁来实现CPU和外围设备之间的数据传递:


《程序是怎样跑起来的》--享受方便同时了解原理_第22张图片

通过中断实现键盘实时显示

I/O端口号、IRQ、DMA通道可以说是识别外围设备的3点组合。不过,IRQ和DMA通道并不是所有的外围设备都必须具备的。计算机主机通过软件控制硬件时所需要的信息的最低限,是外围设备的I/O端口号。IRQ只对需要中断处理的外围设备来说是必需的,DMA通道则只对需要DMA机制的外围设备来说是必需的。假如多个外围设备都设定成同样的端口号、IRQ及DMA通道的话,计算机就无法正常工作了。这种情况下,就会出现“设备冲突”的提示。

显示器显示文字及图形的机制。如果用一句话来简单地概括该机制,那就是显示器中显示的信息一直存储在某内存中。该内存称为VRAM(Video RAM)。在程序中,只要往VRAM中写入数据,该数据就会在显示器中显示出来。实现该功能的程序,是由操作系统或BIOS提供,并借助中断来进行处理的。

VRAM中写入的数据被显示在显示器上:


《程序是怎样跑起来的》--享受方便同时了解原理_第23张图片

在现在的计算机中,显卡等专用硬件中一般都配置有与主内存相独立的VRAM和GPU(Graphics Processing Unit,图形处理器,也称为图形芯片)。这是因为,对经常需要描绘图形的Windows来说,数百兆的VRAM是必需的。而为了提升图形的描绘速度,有时还需要专用的图形处理器(图11-11(b))。但不管怎样,内存VRAM中存储的数据就是显示器上显示的信息,这一机制是不变的。

你可能感兴趣的:(《程序是怎样跑起来的》--享受方便同时了解原理)