计算机与程序是怎样跑起来的?这确实是一个十分有趣的话题。想想计算机功能是如此强大,程序能够完成很多复杂的任务,是不是觉得很神奇?再想想我们这个纷繁的世界和宇宙,有其复杂性也有其简单性,竟然都是由原子和虚空组成的,因为排列组合而变得复杂。计算机硬件、编程语言、程序也是如此。计算机硬件的基本逻辑元件只是一个逻辑开关,用来表示两个状态(称为二进制),经过组合来表示不同的数字,用数字便可以表示万物。程序也是如此,一般只是由几十个关键字、运算符、三个基本控制结构按某种编程语言规范组合起来,由一个翻译程序(按编程语言规范)将程序翻译成二进制序列给计算机执行即可。
0 布尔代数只需要使用一些简单的运算规则和两个符号,如二进制的0或1。布尔代数是英国人布尔(Boole)于1847年提出来的,是数学和逻辑学的结合。
1 布尔代数可以在开关电路中实现,这是美国人香农(Shannon)在1938年提出来的,结合了数学、逻辑学、电学。
2 开关电路中的逻辑开关可以是继电器、或电子管、或晶体管。(是创建计算机最核心的逻辑元件,关系到速度、能耗、稳定性、以及由价格影响到的普及问题)
3 开关电路可以实现逻辑门电路,如与、或、异或电路。
4 逻辑门可以组合成半加器、加法器,由加法器可以实现其它算术和逻辑运算。
5 逻辑门组合也可以实现记忆电路,从而实现存储功能。
6 以上就是计算机实现基本的理论与硬件基础。
7 最早的计算机是专用的,然后具有了通用性,通过插拔电线和外部开关实现计算任务的改变。
8 1945年,美国人冯诺依曼(von Neumann)为了实现计算机全过程的自动化,减少人为在计算前和计算中的人工干预,提出 了“存储程序、程序控制”的概念。
冯诺依曼认为数据和指令同等存储在存储器(内存、寄存器)中,根据编码规则解释读取,由控制器解释指令并产生控制信号,从而实现了计算机的通用性。
如何来实现相同任务的自动化呢?刚开始的“直接编程”是不具有自动化的,即在计算一道题之前,先由操作人员手工把多个部件用电线按一定方式连接起来,再设置一些开关。第二种称为“存储程序”,即先把题目所需要的计算指令序列输入到电脑中存起来,由这些指令来自动地联接部件和设置开关。现今我们使用的计算机都是采用“存储程序控制”的思路。
编码可以分为机器指令编码(组合机器指令编码来解决任务称为机器语言编程)、内存地址和寄存器编码、字符编码、图形编码、声音编码、视频编码等。
9 内存地址和寄存器编码
数据和指令存储到存储器,需要通过地址来访问。
最开始16位CPU内部有20根地址线,其编码区间为:00000H~0FFFFFH,所以,它可直接访问的物理空间为1M(220)字节。而16位CPU内部存放存储单元偏移量的寄存器(如:IP、SP、BP、SI、DI和BX等)都是16位,它们的编码范围仅为:00000H~0FFFFH。这样,如果用16位寄存器来访问内存的话,则只能访问内存的最低端的64K,其它的内存将无法访问。为了能用16位寄存器来有效地访问1M的存储空间,16位CPU采用了内存分段的管理模式,并引用段寄存器的概念。
存储单元中所存放的二进制信息通常称为该存储单元的内容或值,根据数据类型的不同,通过一个或多个内存单元(字节)拼接而成,由其首地址表示。如一个双字的内容是该字地址所指向的单元及其后继三个单元的内容拼接而成。
数据可以是存储中的立即数,也可以是内存单元、还可以是寄存器,可以有多种方法来表示内存单元地址,称为寻址方式。
10 机器指令之操作码编码
一个完整的机器指令通常包含有操作码和操作数(数据,同样需要编码)。
自然,计算机的操作可以通过逻辑开关来控制,n个指令可以通过log2n个二进制数(位,逻辑开关)来表示,如一个字节(8个位)便可以表示255个机器指令,如:
11 数据编码之数值编码
有表示整数的补码、表示浮点数的IEEE754编码方案等。
12 数据编码之字符编码
字符需要另外一套编码规则,如ASCII、GB2312、Unicode等,用一个数字来表示一个字符(字符的显示需要另外一套编码规则来解释,这就是图形编码,后面简单解释),字符越多,需要的数字越多(还要考虑规律的问题),也就是需要的二进制位(存储空间)更多,所以如何经济地存储是需要考虑的问题,对于ASCII全码,因为只使用了一个字符,存储没什么问题,但如果一套符号体系需考虑更多的字节呢?
1个字节 1-256
2个字节 1-65536
3个字节 1-16777216
就只是理论上表示的字符数,因为要考虑规律的问题,实际用于编码的序列号要少很多,如GB2312的规则之一就是兼容ASCII,将ASCII码以外的字符的首位编码都是1。
如果编码的字符达几十万,如unicode,需要考虑的字节数可以就是4个或以上,毫无疑问,前面的字符一个字节就够,只有后面的字符才需要更多的字节,为此,又搞出了一套存储方案uft-8、uft-16、utf-32,实现等长或不等长的存储,但应有自己的规则和与unicode对应的规则。
对于字符编码,除了表示、存储、显示的问题,还有输入的问题,如果你要输入字母a,是否需要考虑其ASCII编码呢,a的ASCII编码是97,为什么不从十进制的101开始编小写字母呢,其实97的二进制数1100001比十进制的100更有规律。A的编码65也是如此(2^6=64)。ASCII可输入字符可以直接从键盘输入,其内部再做转换。
多字节编码的汉字就不行了,你又不能去记其编码后,为此又搞出来了一些输入的编码方案,如五笔,拼音输入等。
13 数据编码之图形图像编码
图形图像包括点阵表示的位图和函数表示的矢量图。
13.1 位图
黑白图像就好比在其表面划分出精细的小方格,每一方格称为一个像素。若把全白的像素设定为11111111,全黑的像素设定为00000000,具有不同明暗的灰色介于两者之间,则8比特就具有256种灰度的一个像素数字化的基础。你完全可以使用更多的比特来保存一个像素的信息,这些信息既可以代表黑白层次,也能够代表不同的彩色。事实上,多媒体电脑屏幕上每一像素的颜色已经超过数百万种之多,十分逼真地接近自然色泽。把所有的像素组合起来,图像或照片也就“数字化生存”于电脑屏幕、数字电视屏幕或彩色打印机纸上。
如bmp,以及压缩存储的jpg、png等。
13.2 矢量图:
如CAD的swf,由直接和曲线组成,可以直接用公式进行描述和绘制。
14 声音编码
声音其实是一种空气中的振动,声音通过话筒(利用电磁感应原理)转变为时间上连续的电流(电压波),电流(电压波)与引起电流(电压波)的声波的变化规律是一致的,因此可以利用电流(电压波)来模拟声音信号,这种电流(电压波)被称为模拟音频信号。对模拟信号采样、量化,便可以将模拟音频信号转化为一组用来表示声音的二进制数字序列-数字音频。至此,我们就成功地将声音数字化了。当我们听音乐时则是一个相反的过程。只要你听过CD激光唱片播放的立体音乐,对此就会有切身的感受。CD激光盘上布满了极其微波的凹坑,每一个凸凹分别表示“0”,“1”的信息,音乐或声音就以这一系列的凸凹方式,“数字化生存于光盘表面。
声音编码也就是音频,如mp3编码标准。
15 视频编码
一幅一幅静态的图像连续播放,又可构成动态的卡通片。配上悦耳动听的音乐,附上文字字幕,再经过压缩和解压,电影、电视和多媒体电子图书既能在光盘或磁盘上“数字化生存”,也可以通过互联网络传输到每一角落,“数字化生存”于整个地球。
视频编码也就是音频与图形图像的结合,如mp4标准。
16 从机器指令到汇编指令
一个机器指令通常包含有操作数,一个完整的机器指令编码需要考虑操作码、寻址方式、操作数,具体的编码规则可以通过查表获得。
查表不正是计算机所擅长的吗?如果用更容易理解和记忆的英文单词或英文缩写去表示机器指令,这样的单词或英文缩写就称为汇编指令,并通过一个翻译程序去将对应的汇编指令翻译成机器指令,这样的编程语言称为汇编语言,相对于用机器语言(对应一个机器指令集),汇编语言更方便编写、阅读和维护。
简单一点理解,汇编语言就是通过建立 机器指令与汇编指令的对照表,然后由汇编器去做查找、替换。
17 从汇编指令到高级语言指令
用汇编指令编程还是比较繁琐,计算机的翻译程序似乎可以代替程序员做更多的工作。这样的翻译程序就是现在的编译器或解释器,是一种更高程度上的抽象,称为高级语言。一条高级语言语句一般可以对应一条或多条 的汇编语句(机器指令语句)。高级语言的设计者设计语法规则,程序员按规则编写解决问题的代码,编译器(设计时要考虑高级语言的语法规则、操作系统(在机器指令集上构建的基础应用))按规则翻译,当然规则的设计有其合理性。
17.1 面向过程的控制结构
在汇编语言中,有通过有无条件或有条件跳转(cmp指令影响标志寄存器实现)实现循环,或通过用ecx寄存器作为循环计数器来实现loop循环,也可以使用伪指令实现循环结构。
跳转可以实现条件分支和循环的效果。
当计算机编程尚处于起步阶段时,程序流程是由“GOTO”语句来控制。该类语句允许程序员对当前代码行断行,而直接进入另一个不同的代码段。
编程语言后来引入了函数的概念,即允许程序对代码进行断行。如果已经完成,不再使用goto语句来表示代码的断行。函数调用后,函数将回到下一条指令。其中一个主要的原因是,一个遍布goto语句的程序会让让人很难抓住重心,不便于对程序的理解和维护。
GOTO语句一直是批评和争论的目标,主要的负面影响是使用GOTO语句使程序的可读性变差,甚至成为不可维护的“面条代码”。随着结构化编程在二十世纪六十年代到七十年代变得越来越流行,许多计算机科学家得出结论,即程序应当总是使用被称为“结构化”控制流程的命令,如if, else, switch, while, for等关键字和代码块实现的条件分支与循环。
17.2 机器码、汇编代码、C代码的比较
17.3 面向对象的封装、继承、多态
引入了控制结构的面向过程思路虽然有其优越性,但模块性还是不强,因为大型程序的构建,如果能使用搭积木的方式是最好的,为此,在有了面向对象的编程思维,对象就像一块块的预制件,先创建预制架构模板(类),按预制架构模板创建预制件(对象)。
面向对象的封装技术,分离了内部实现和外部接口,当程序扩充时,可以将代码的变更产生的影响缩小到最小的范围。
对于大型程序而言,相对于面向过程思想构建的代码,面向对象在代码的编写、维护方面更有优势。
17.4 面向过程与面向对象的对比
17.5 面向过程与面向对象的代码比较
18 程序的编码、连接
程序运行的硬件平台:CPU指令系统;
程序运行的操作系统平台;
需要处理的数据有哪些?找到数据的规律或让其更有规律;(数据结构)
怎样将数据输入到内存?
数据如何处理?(算法实现)
数据如何从内存输出到显示屏或打印机、文件、数据库、网络?
选择计算机高语言、开发框架和对应的开发工具,将上述的步骤用计算机高级语言描述出来(利用开发工具的编辑框编辑代码)?
利用开发工具的编译器编译代码,此过程还包括利用开发工具的预处理器进行编译前的预处理(如宏展开、库文件包含(静态链接)、条件编译),以及使用调试器进行代码调试;
用计算机语言对应的的编译器编译成计算机能理解的由“0”和“1”组成的二进制代码(也可是程序运行时直接用计算机语言对应的解释器直接解释成二进制代码)。
编译完成后形成一个exe文件,这个文件可能要求在运行时需要动态加载DLL库;
19 程序安装(如有需要,小程序及绿色程序可直接运行)
19.1 在硬盘的某一位置创建一个专门的文件夹;
19.2 将需要的文件从硬盘的另一位置(下载后存放位置)或光盘复制到上述文件夹;
19.3 拷贝和注册相关DLL文件到自己的安装目录或相关系统目录下;
19.4 软件的设置参数与DLL文件的注册信息写进注册表;
19.5 上述的大型软件由于涉及的文件、配置较多,一般会采用专业安装程序制作工具,这样的安装文件会有详细的选项,绿色软件则不需注册,可直接运行;
19.6 以上创建文件夹,复制文件,写入注册表等操作为避免用户的不便操作,程序开发人员会采用专业安装程序制作工具制作安装文件,由此也可以通过更改增加安装包的适当参数让程序安装自动完成,也可以利用第三方软件录制一次软件安装过程然而让软件以后安装时可以自动运行。
广义的绿色就是指不需要专门的安装程序,对系统的改变比较少,手工也可以方便的完成这些改变,比如拷贝几个动态库,或者导入注册表,这里的关键是手工可以方便的完成这些改变,或者可以借助于批处理等等脚本完成。
狭义的绿色可以叫做纯绿色软件,就是指这个软件对现有的操作系统部分没有任何改变,除了软件现在安装的目录,应该不往任何地方写东西,删除的时候,直接删除所在的目录就可以了,就类似于以前的大多数DOS程序。
20 程序运行过程
20.1 双击exe文件,操作系统创建一个新的进程和一个初始线程;
20.2 应用程序代码装载到内存;
20.3 动态链接库装载到内存(加载时动态链接库(指定路径),如有需要及exe中有此功能代码);
20.4 为数据和堆栈分配物理内存,并映射到虚拟内存;
20.5 应用程序开始执行(运行时动态链接库(按顺序搜索指定的几个路径),如有需要及exe中有此功能代码)。