矢泽久雄, 日本YAZAWA股份有限公司董事长兼总经理。
计算机是怎样跑起来的
How Computer Works
1~2 计算机
计算机的三大原则:
1.计算机是执行输入、运算、输出的机器
2.程序是指令和数据的集合
3.计算机的处理方式有时与人们的思维习惯不同
3 汇编
程序的作用是驱动硬件工作。
计算机的硬件有三个基本要素,CPU、内存、I/O。
时钟信号的频率,就是由时钟发生器发送给CPU的电信号的频率。
机器语言就是处理器可以直接理解(与生俱来就能理解)的编程语言。机器语言有时也叫作原生代码(Native Code)。
汇编语言的语法,即把“标签”、“操作码(指令)”、“操作数(指令的对象)”并排写在一行上。
使用汇编语言编程时,因为要事无巨细地列出计算机的行为,所以程序会变得冗长繁复。
4 程序流程
程序是流动着的。
程序的流程只有顺序执行、条件分支和循环这三种:
顺序执行是最基本的程序流程,这是因为CPU中的PC寄存器的值会自动更新。
条件分支和循环,
在高级语言中用程序块表示,
在机器语言和汇编语言中用跳转指令表示,
在硬件上是通过把PC寄存器的值设为要跳转到的目的地的内存地址来实现。
条件分支本身也是通过跳转指令实现的。
根据比较操作的结果,跳转到之前处理过的步骤就是循环;跳转到之后尚未处理的步骤就是条件分支。
结构化程序设计就是“为了把程序编写得具备结构性,仅使用顺序执行、条件分支和循环表示程序的流程即可,而不再使用跳转指令”。
程序的流程是由程序块表示的,而不是用GoTo语句等跳转指令实现的。
算法(Algorithm),就是解决既定问题的步骤。
思考算法时的要点是要分两步走,先从整体上考虑程序的粗略流程,再考虑程序各个部分细节的流程。
中断处理是指计算机使程序的流程突然跳转到程序中的特定地方(中断处理例程 Routine / 中断处理程序 Handler)。
这种跳转是通过CPU所具备的硬件功能实现的。
事件驱动:用户的操作等产生事件后,由事件决定程序的流程。
状态转化图:表示事件驱动;有多个状态,反映了由于某种原因从某个状态转化到另一个状态的流程。
电阻颜色代码的谐音助记口诀:
数字 | 颜色 | 谐音助记口诀 |
---|---|---|
0 | 黑 | 黑灵(零)芝 |
1 | 棕 | 粽(棕)子叶 |
2 | 红 | 红孩儿(二) |
3 | 橙 | 三乘(橙)轿 |
4 | 黄 | 黄丝(四)带 |
5 | 绿 | 五缕(绿)须 |
6 | 蓝 | 蓝琉(六)璃 |
7 | 紫 | 钟子(紫)期(七) |
8 | 灰 | 灰八哥 |
9 | 白 | 摆(白)酒(九)宴 |
5 算法
“哨兵”:一种含有特殊值的数据,可用于标识数据的结尾等。
算法的定义:被明确定义的有限个规则的集合,用于根据有限的步骤解决问题。
算法中解决问题的步骤是明确且有限的。
计算机不靠直觉而是机械地解决问题。
主要的典型算法:
名称 | 用途 |
---|---|
辗转相除法 | 求解最大公约数 |
埃拉托斯特尼筛法 | 判定素数 |
顺序查找 | 检索数据 |
二分查找 | 检索数据 |
哈希查找 | 检索数据 |
冒泡排序 | 数据排序 |
快速排序 | 数据排序 |
6 数据结构
算法(处理问题的步骤)和数据结构(作为处理对象的数据的排列方式)。
只要灵活地去运用典型算法和数据结构,就能创造出出色的原创作品,而能够创造出原创作品的程序员才是真正的技术者。
7 面向对象编程
面向对象编程就是通过把组件拼装到一起进行编程的方法。
面向对象编程的程序设计方法:将关注点置于对象(Object)本身,对象的构成要素包含对象的行为及操作,以此为基础进行编程。
所使用的主要编程技巧有继承、封装、多态三种。
面向对象编程的关键在于能否灵活地运用类。
用“函数”表示指令,用“变量”表示数据。对于C语言或是BASIC的程序员而言,程序就是函数和数据的集合。
所谓企业级的程序,指的是对可维护性有较高要求的程序。可维护性体现在当程序投入使用后对已有功能的修改和新功能的扩充上。
消息传递:程序可以通过由一个对象去调用另一个对象所拥有的函数这种方式运行起来。
面向对象语言中的消息传递,指的就是调用某个对象所拥有的函数。
使用类的程序员可以通过三种方法使用类:
1.仅调用类所持有的个别成员(函数和变量);
2.在类的定义中包含其他的类(这种方法被称作组合);
3.通过继承已存在的类定义出新的类。
Java和.NET其实是位于操作系统(Windows或Linux等)之上,旨在通过隐藏操作系统的复杂性从而提升开发效率的程序集(框架)。
框架由两部分构成,一部分是负责安全执行程序的“执行引擎”,另一部分是作为程序组件集合的“类库”。
UML中规定的九种图:
名称 | 主要用途 |
---|---|
用例图 Use Case Diagram | 表示用户使用程序的方式 |
类图 Class Diagram | 表示类以及多个类之间的关系 |
对象图 Object Diagram | 表示对象 |
时序图 Sequence Diagram | 从时间上关注并表示多个对象间的交互 |
协作图 Collaboration Diagram | 从合作关系上关注并表示多个对象间的交互 |
状态图 State Diagram | 表示对象状态的变化 |
活动图 Activity Diagram | 表示处理的流程等 |
组件图 Component Diagram | 表示文件以及多个文件之间的关系 |
配置图 Deployment Diagram | 表示计算机或程序的部署配置方法 |
8 数据库
数据库系统的构成要素:数据文件,DBMS,应用程序。
记录(行/元组Tuple):录入到表中的每一行数据。
字段(列/属性Attribute):构成一条记录中的各个数据项所在的列。
外键用于设定表和表之间的关系(Relationship)。
索引是提升数据检索速度的机制。
索引仅仅是提升数据检索和排序速度的内部机制。一旦在字段上设置了索引,DBMS就会自动为这个字段创建索引表。
一旦设置了索引,每次向表中插入数据时,DBMS都必须更新索引表。
提升数据检索和排序速度的代价,就是插入或更新数据速度的降低。因此,只有对那些要频繁地进行检索和排序的字段,才需要设置索引。
连接表(Link Table):当出现多对多关系时,可以在这两张表之间再加入一张表,把多对多关系分解成两个一对多关系。
规范化,就是将一张大表分割成多张小表,然后再在小表之间建立关系,以此来达到整理数据库结构的目的。
在设计系统时,优先设计数据库,再设计用户界面。
使用数据对象向DBMS发送SQL语句。
ADO = ActiveX Data Object ActiveX数据对象
ADO是以下几个类的统称:
用于建立和DBMS连接的Connection类
向DBMS发送SQL语句的Command类
存储DBMS返回结果的Recordset类等
事务由若干条SQL语句构成,表示对数据库一系列相关操作的集合。
1.BEGIN TRANSACTION(开启事务)语句,用于通知DBMS开启事务;
2.COMMIT(提交事务)语句,用于通知DBMS提交事务;
3.ROLL BACK(事务回滚)语句,用于在事务进行中发生问题时,把数据库中的数据恢复到事务开始前的状态。
9 TCP/IP网络
协议(Protocol):对信息发送方式的规定或约束。为了交换信息,必须在发送者和接收者之间事先确定发送方式。
CSMA/CD = Carrier Sense Multiple Access with Collision Detection 带冲突检测的载波监听多路访问
载波监听(Carrier Sense),指的是这套机制会去监听(Sense)表示网络是否正在使用的电信号(Carrier)。
多路复用(Multiple Access)指的是多个(Multiple)设备可以同时访问(Access)传输介质。
带冲突检测(with Collision Detection)则表示这套机制会去检测(Detection)因同一时刻的传输而导致的电信号冲突(Collision)。
MAC = Media Access Control
通常把IP地址中表示分组(即LAN)的部分称作“网络地址”、表示各台计算机(即主机)的部分称为“主机地址”。
子网掩码 Subnet Mask:
子网掩码的作用是标识出在32比特的IP地址中,从哪一位到哪一位是网络地址,从哪一位到哪一位是主机地址。
子网掩码中,值为1的那些位对应着IP地址中的网络地址,后面值为0的那些位则对应着主机地址。
DHCP = Dynamic Host Configuration Protocol 动态主机设置协议
DHCP服务器上记录着可以被分配到LAN内计算机的IP地址范围和子网掩码的值。作为DHCP客户端的计算机在启动时,就可以从中知道哪些IP地址还没有分配给其他计算机。
“默认网关”的配置项。通常会把路由器的IP地址设置在这里。也就是说路由器就是从LAN通往互联网世界的入口(Gateway)。路由器的IP地址也可以从DHCP服务器获取。
路由器,是决定数据传输路径的设备。
路由器的工作原理就是查看附加到数据上的IP地址中的网络地址部分,只要发现这个数据不是发送给LAN内计算机的,就把它发送到LAN外,即互联网的世界中。
# 列出路由表
route print
# 查看路由器的路由过程
# tracert 主机名
tracert www.grapecity.com
路由表由5列构成:
Network Destination、Netmask、Gateway、Interface 这四列记录着数据发送的目的地和路由器的IP地址等信息。
Metric这一列记录着路径的权重,这个值由某种算法决定,比如数据传输过程中经过的路由器的数量。
路由(Routing):数据经过路由器转发的过程。
DNS服务器可以把主机名解析成IP地址。
DNS服务器通常被部署在各个LAN中,里面记录着FQDN和IP地址的对应关系表。
FQDN = Fully Qualified Domain Name 完整限定域名:由主机名和域名组合起来形成的名字。
# 查看域名对应的 IP 地址
nslookup
ARP = Address Resolution Protocol 地址解析协议:IP地址到MAC地址的转换。
# 输出ARP的缓存表
arp -a
IP协议用于指定数据发送目的地的IP地址以及通过路由器转发数据。
TCP协议则用于通过数据发送者和接收者相互回应对方发来的确认信号,可靠地传输数据。
实现了TCP/IP网络的程序的层级:
(数据经过实现了各层协议的软件或硬件,一层一层地传递下去)
用户
应用程序(Web或电子邮件)
实现了TCP协议的程序
实现了IP协议的程序
设备驱动程序
网卡
网线
10 加密数据
XOR运算 = eXclusive OR 逻辑异或运算。异或运算,翻转加密,再翻转解密。
密钥每增长一位,破解所花费的时间就会翻10倍。
印章或签字有两层约束。其一是发送者承认文件的内容是完整有效的;其二是文件确实是由发送者本人发送的。
合理的密钥应该满足如下条件:长短适中、可以反复使用、可以通过某种通信手段交给接收者,并且通信双方以外的其他人难以用它来解密。
创建公钥和私钥的步骤:
[创建公钥的步骤]
(1) 选取两个素数a、b
例如a=17、b=19
(2) 求出c=a×b
c=17x19=323
(3) 求出d=(a-1)x(b-1)
d=(17-1)x(19-1)=288
(4) 选取与d没有公约数的e
e=11
(5) 把c和e这两个数值组成的数对儿作为公钥
c=323、e=11
[创建私钥的步骤]
(1) 求出f,使其满足(fxe)÷d余1
例加f=131
(2) 把c和f这两个數值组成的数对儿作为私钥
c=323、f=131
11 XML
标记语言,就是可以用标签为数据赋予意义的语言。
元语言:用于定义新语言的语言。通过使用XML可以定义出各种各样的新语言。
元注解,用于定义新注解的注解。
元编程,用于创建新程序的程序。
元数据,用于描述新数据的数据。
元,原本,根源……
HTML | XML | |
---|---|---|
全称 | Hypertext Markup Language 超文本标记语言 | Extensible Markup Language 可扩展标记语言 |
定义 | 用于编写网页的固定的标记语言 | 用于定义任意标记语言的元语言 |
使用 | 只能使用定义的若干种标签 | 不限定标签种类,可任意创建标签 |
用途 | 仅限于信息的可视化,用于展现网页 | 在互联网上交换信息 |
概述 | 给人看的 | 给计算机看的 |
命名空间,通常是一个能代表企业或个人的字符串,用于修饰限定标签的名字。
XML命名空间(Namespace in XML),旨在防止同形异义带来的混乱。
在XML文档中,通过把“xmlns=”命名空间的名字””作为标签的一个属性记述,就可以为标签设定命名空间。
xmlns = XML NameSpace(命名空间),通常用全世界唯一的标识符作为命名空间的名称。
XML中的主要约束:
约束 | 示例 |
---|---|
XML文档的开头要写有XML声明,表明使用的XML版本和宇符编码 | <?xml version="1.0" encoding="UTF-8"?> |
信息要用开始标签<标签名> 和结束标签</标签名> 括起来 |
<cat>小玉</cat> |
标签名不能以数字开头,中间也不能含有空格 | 不能用<5cat>或<my cat>作标签名 |
半角空格、换行符、制表符(TAB)都会被视为空白字符,在文档中可以任意地换行或缩进书写 | |
没有内容的元素,可以写成<标签名></标签名> 或<标签名/> |
<cat></cat>等价于<cat/> |
标签名区分大小写 | <cat>、<Cat>、<CAT> 互不相同 |
标签中可以嵌套标签以表示层级结构,但是不能交叉嵌套 | |
在XML声明的后面,必须有且只有一个“根元素”,该标签包舍了所有其他的标签 | <pet>…其它的标签…</pet> |
在开始标签中,可以以属性名="属性值" 形式加入任意的属性 |
<cat type="三色猫">小玉</cat> |
特殊符号要转义:< => < > => > & => & ' => ' " => " |
<cat>小玉&小老虎</cat> |
<![CDATA[...]]> ,可以直接使用特殊符号和大量输入 |
<cat><![CDATA[小玉&小老虎&咪咪]]></cat> |
注释的写法:<!- ... -> |
<!-- 注释 --> |
DTD = Document Type Definition 文档类型描述
格式良好的XML文档(Well-formed XML Document):遵循XML约束、正确标记了的文档。也就是能通过XML解析器的解析。
有效的XML文档(Valid XML document):在XML文档中写有DTD信息。
完整的XML文档包括三个部分:
- XML声明:写在XML文档开头的、形如<? xml version=”1.0” encoding=”UTF-8”? >的部分。
- DTD:作用是定义XML实例的结构,可以省略。
- XML实例:文档中通过标签被标记的部分。
用XML定义的标记语言示例:<!-- XML声明 --> <?xml version="1.0" encoding="UTF-8"?> <!-- DTD --> <!DOCTYPE mydata [ <!ELEMENT mydata (company+)> <!ELEMENT company (name, address, employee)> <!ELEMENT name (#PCDATA)> <!ELEMENT address (#PCDATA)> <!ELEMENT employee (#PCDATA)> ]> <!-- XML实例 --> <mydata> <company> <name>小明</name> <address>中国</address> <employee>1000</employee> </company> <company> <name>小红</name> <address>地球</address> <employee>2000</employee> </company> </mydata>
名称 | 全称 | 用途 | 有关的企业或组织 |
---|---|---|---|
XSL | eXtensible Stylesheet Language 可扩展样式语言 | 为XML中的信息提供显示格式 | W3C |
MathML | Mathematical Markup Language 数学标记语言 | 描述数学算式 | W3G |
SMIL | Synchronized Multimedia Integration Language 同步多媒体集成语言 | 把多媒体数据嵌入到网页中 | W3G |
MML | Medical Markup Language 医疗标记语言 | 描述电子病历 | 电子病历研究会 |
SVG | Scalable Vector Graphics 可缩放矢量图形 | 用向量表示国形数据 | W3C |
Jepax | 表示电子书 | 日本电子出版协会等 | |
WL | 表示移动终端上的内容 | WAP Forum | |
CHTML | Compact HyperText Markup Language 压缩式超文本标记语言 | 表示手机上的内容 | Accos等6家公司 |
XHTML | eXtensible HyperText Markup Language 可扩展超文本标记语言 | 用XML定义HTML4.0 | W3C |
SOAP | Simple Object Access Protocol 简单对象访问协议 | 实现分布式计算 | W3C |
SGML = Standard Generalized Markup Language 标准通用标记语言
分布式计算,就是把程序分散部署在用网络连接起来的多台计算机上,使这些计算机相互协作,充分发挥计算机整体的计算能力。
12 SE 系统工程师
IT = Information Technology 信息技术
SE = System Engineer 系统工程师:负责监管计算机系统的构建。
是自始至终参与系统开发过程的工程师,而不是只负责编程的程序员。
要具备的能力分为两类:
- 技术能力(Technical Skill),是指灵活运用硬件、软件、网络、数据库等技术的能力。
- 沟通能力(Communication Skill),是指和他人交换信息的能力,要求的是双向的信息交换能力。
客户最关心的是使用计算机解决眼前的问题,而并不是引进什么样的计算机系统。
倾听客户的难处,给出解决对策即IT解决方案,这才是SE的职责。
面向对象 -> 换位思考,站在客户或对方的角度看问题。
需要的技能:
职业 | 工作内容 | 所需技能 |
---|---|---|
SE | 调查、分析客户的业务内容,计算机系统的基本设计,确定计算机系统的规格,估算开发费用和开发周期,项目管理,软件开发管理,计算机系统的维护管理 | 倾听需求,书写策划率,硬件,软件,网络,数据库,管理能力 |
程序员 | 制作软件(编程) | 编程语言,算法和数据结构,关于开发工具和程序组件的知识 |
系统是由多个要素相互发生关联、结合而成的带有一定功能的整体。
计算机系统是将各种各样的硬件和软件组合起来构建而成的系统。
所谓设计,就是拆解。
无论任何事都需要规范,即便未能按其实践,规范的存在也算是一种参考。
只有以易于维护为标准把业务拆解成对象的做法,才是具有专家风范的面向对象法。
瀑布模型各个阶段的文档:
阶段 | 文档 |
---|---|
需求分析 | 系统策划文档、系统功能需求规格文档 |
外部设计 | 外部设计文档 |
内部设计 | 内部设计文档 |
程序设计 | 程序设计文档 |
编码实现 | 模块设计文档、测试计划文档 |
测试 | 测试报告 |
部署、维护 | 部署手册、维护手册 |
部署指的是将计算机系统引进(安装)到客户的环境中,让客户使用。
维护指的是定期检查计算机系统是否能正常工作,根据需要进行文件备份或根据应用场景的变化对系统进行部分改造。
具有代表性的程序设计方法:
设计方法 | 拆解时所关注的事物 |
---|---|
通用功能分割法 | 在整个计算机系统中通用的功能 |
STS法 | 数据流(输入、变换、输出) |
TR法 | 事务(数据的处理单位) |
Jackson法 | 输入数据和输出数据 |
Warnier法 | 输入数据 |
面向对象法 | 构成计算机系统的事务(对象) |
将计算机系统的构成要素设成多机备份,可以出乎意料地大幅度提升设备利用率。设备利用率 = 正常运转的时间 / (正常运转的时间 + 出现故障处于维修状态的时间)
专家也好普通人也罢,只有为社会做出了贡献才能有成就感,才会觉得工作有意义。
点评:浅显易懂,适合新手入门。
程序是怎样跑起来的
How Program Works
CPU
CPU的内部由寄存器、控制器、运算器和时钟四个部分构成,各部分之间由电流信号相互连通。
对程序员来说,CPU是具有各种功能的寄存器的集合体。
寄存器的主要种类和功能:
种类 | 功能 |
---|---|
累加寄存器(accumulator register) | 存储执行运算的数据和运算后的数据 |
标志寄存器(flag register) | 存储运算处理后的 CPU 的状态 |
程序计数器(program counter) | 存储下一条指令所在内存的地址 |
基址寄存器(base register) | 存储数据内存的起始地址 |
变址寄存器(index register) | 存储基址寄存器的相对地址 |
通用寄存器(general purpose register) | 存储任意数据 |
指令寄存器(instruction register) | 存储指令。CPU 内部使用,程序员无法通过程序对该寄存器进行读写操作 |
栈寄存器(stack register) | 存储栈区域的起始地址 |
机器语言指令的主要类型和功能:
类型 | 功能 |
---|---|
数据转送指令 | 寄存器和内存、内存和内存、寄存器和外围设备之间的数据读写操作 |
运算指令 | 用累加寄存器执行算术运算、逻辑运算、比较运算和移位运算 |
跳转指令 | 实现条件分支、循环、强制跳转等 |
call/return 指令 | 函数的调用/返回调用前的地址 |
函数调用使用的是 call 指令,而不是跳转指令。return 命令的功能是把保存在栈中的地址设定到程序计数器中。
二进制
计算机处理信息的最小单位——位,就相当于二进制中的一位。位的英文 bit 是二进制数位(binary digit)的缩写。
字节是信息的基本单位。
位权是用来与各数字位的数字相乘的数值。
将二进制数的值取反后加 1 的结果,和原来的值相加,结果为 0。
只有在右移时才必须区分逻辑位移(最高位补0)和算术位移(最高位补符号位0或1)。左移时,无论是图形模式(逻辑左移)还是相乘运算(算术左移),都只需在空出来的低位补 0 即可。
符号扩充就是指在保持值不变的前提下将其转换成 16 位和 32 位的二进制数。
不管是正数还是用补数表示的负数,都只需用符号位的值(0 或者 1)填充高位即可。
将二进制数表示的信息作为四则运算的数值来处理就是 算术。而像图形模式那样,将数值处理为单纯的 0和 1 的罗列就是 逻辑。
计算机能处理的运算,大体可分为算术运算和逻辑运算。
算术运算是指加减乘除四则运算。
逻辑运算是指对二进制数各数字位的 0 和 1 分别进行处理的运算,包括逻辑非(NOT 运算)、逻辑与(AND 运算)、逻辑或(OR 运算)和逻辑异或(XOR 运算)四种。
“逻辑非是所有位的取反操作”
“逻辑与是将一部分变为 0(复位到 0)的操作”
“逻辑或是将一部分变为 1(复位到 1)的操作”
“逻辑异或是将一部分进行取反(相同取 0,不同取 1)的操作”
小数
计算机是功能有限的机器,无法直接处理循环小数。
浮点数是指用符号、尾数、基数和指数这四部分来表示的小数。
浮点数的表现形式由符号、尾数、基数、指数四部分构成。
±m×n^e
双精读浮点数,共64位。符号部分1位,指数部分11位,尾数部分52位。
单精度浮点数,共32位。符号部分1位,指数部分8位,尾数部分23位。
内存
高级编程语言中的数据类型表示的是占据内存区域的大小和存储在该内存区域的数据类型。
ROM(Read Only Memory)是一种只能用来读取的内存。
RAM(Random Access Memory)是可被读取和写入的内存,分为:
- 需要经常刷新(refresh)以保存数据的 DRAM(Dynamic RAM)
- 不需要刷新电路即能保存数据的 SRAM(Static RAM)
将多字节数据的低位字节存储在内存低位地址的方式称为低字节序。
把数据的高位字节存储在内存低位的方式称为高字节序。
在程序中,通过明确标记数据类型来记述变量的过程称为定义变量。
指针的数据类型表示一次可以读写的长度,即从指针存储的地址中一次能够读写的数据字节数。
数组是指多个同样数据类型的数据在内存中连续排列的形式。
数组的定义中所指定的数据类型,也表示一次能够读写的内存大小。
数组是内存的使用方法的基础。
栈的原意是“干草堆积如山”。
队列一般是以环状缓冲区(ring buffer)的方式来实现的。
链表使元素的追加和删除更容易。
二叉查找树使数据搜索更有效。
磁盘
磁盘在物理方面只能以扇区为单位进行读写。
磁盘缓存 Disk Cache 指的是把从磁盘中读出的数据存储到内存空间中的方式。当该数据再次被读取时,不是从磁盘而是直接从内存中高速读出。提高访问速度。
虚拟内存 virtual memory 是把磁盘的一部分作为假想内存来使用的机制。借助虚拟内存,哪怕是内存容量不足的计算机,也可以运行很大的程序。
磁盘缓存是假想的磁盘(实际上是内存),虚拟内存是假想的内存(实际上是磁盘)。
利用电流来实现存储的内存,利用磁效应来实现存储的磁盘。
从存储容量来看,内存是高速高价,而磁盘则是低速廉价。
内存主要是指主内存(负责存储 CPU 中运行的程序指令和数据的内存),磁盘主要是指硬盘。
程序保存在存储设备中,通过有序地被读出来实现运行,这一机制称为存储程序方式(程序内置方式)。
存储在磁盘中的程序需要读入到内存后才能运行。因为负责解析和运行程序内容的 CPU,需要通过内部程序计数器来指定内存地址,然后才能读出程序。即使 CPU 可以直接读出并运行磁盘中保存的程序,由于磁盘读取速度慢,程序的运行速度还是会降低。
虚拟内存的方法有分页式和分段式两种。
Windows 采用的是分页式。该方式是指,在不考虑程序构造的情况下,把运行的程序按照一定大小的页(page)进行分割,并以页为单位在内存和磁盘间进行置换。
在分页式中,把磁盘的内容读出到内存称为 Page In,把内存的内容写入磁盘称为Page Out。
一般情况下,Windows 计算机的页的大小是 4KB。把大程序用 4KB 的页来进行切分,并以页为单位放入磁盘(虚拟内存)或内存中。
为了实现虚拟内存功能,Windows 在磁盘上提供了虚拟内存用的文件(page file,页文件)。该文件由 Windows 自动做成和管理。文件的大小也就是虚拟内存的大小,通常是实际内存的相同程度至两倍程度。通过 Windows 的控制面板,可以查看或变更当前虚拟内存的设定。
节约内存的编程方法:
- 通过 DLL 文件实现函数共有DLL()文件。
DLL = Dynamic Link Library 动态链接库:是在程序运行时可以动态加载 Library(函数和数据的集合)的文件。
函数的加载方式有静态链接和动态链接两种。 - 通过调用 _stdcall 来减小程序文件的大小。
_stdcall = standard call 标准调用
Windwos 提供的 DLL 文件内的函数,基本上都是 _stdcall 调用方式。这主要是为了节约内存。
用 C 语言编写的程序内的函数,默认设置都不是 _stdcall。C 语言特有的调用方式称为 C 调用。
C 语言之所以默认不使用 _stdcall,是因为 C 语言所对应的函数的传入参数是可变的(可以设定任意参数),只有函数调用方才能知道到底有多少个参数,而这种情况下,栈的清理作业便无法进行。
不过,在 C 语言中,如果函数的参数数量固定的话,指定 _stdcall 是没有任何问题的。
C 语言中,在调用函数后,需要执行栈清理处理指令。栈清理处理是指,把不需要的数据从接收和传递函数的参数时使用的内存上的栈区域中清理出去。该命令不是程序记述的,而是在程序编译时由编译器自动附加到程序中的。编译器默认将该处理附加在函数调用方。在被调用方进行清理处理可节约内存。
磁盘的物理结构是指磁盘存储数据的形式。
磁盘是通过把其物理表面划分成多个空间来使用的。划分的方式有:
- 扇区方式:将磁盘划分为固定长度的空间。
- 可变长方式:把磁盘划分为长度可变的空间。
一般的 Windows 计算机所使用的硬盘和软盘,采用的都是扇区方式。
扇区方式中,把磁盘表面分成若干个同心圆的空间就是磁道,把磁道按照固定大小(能存储的数据长度相同)划分而成的空间就是 扇区。
扇区是对磁盘进行物理读写的最小单位。
Windows 中使用的磁盘,一般 1 个扇区是 512 字节。不过,Windows 在逻辑方面(软件方面)对磁盘进行读写的单位是扇区整数倍 簇。
磁盘的数据保存是以簇为单位来进行。
压缩
压缩文件的扩展名有 LZHA 和 ZIPB 等。
LZH 是用 LHA 等工具压缩过的文件的扩展名。该压缩格式有时也称为 LZH 格式。
ZIP 是用 PKZIP 等工具压缩过的文件的扩展名。该压缩格式有时也称为 ZIP 格式。
文件是字节数据的集合体。
压缩后同压缩前文件大小的比率,称为压缩比率或压缩比。
能还原到压缩前状态的压缩称为可逆压缩,无法还原到压缩前状态的压缩称为 非可逆压缩。
RLE(Run Length Encoding,行程长度编码)算法,把文件内容用“数据×重复次数”的形式来表示的压缩方法。通过数据的重复次数来实现压缩。
哈夫曼算法,是指为各压缩对象文件分别构造最佳的编码体系,并以该编码体系为基础来进行压缩。
用什么样式的编码(哈夫曼编码)对数据进行分割,就要由各个文件而定。用哈夫曼算法压缩过的文件中,存储着哈夫曼编码信息和压缩过的数据。
按照“出现频率高的字符用尽量少的位数编码来表示”这一原则
图像文件的使用目的通常是把图像数据输出到显示器、打印机等设备上。
Windows 的标准图像数据形式为 BMP,是完全未压缩的。由于显示器及打印机输出的 bit(点)是可以直接映射(mapping)的,因此便有了 BMP = bitmap 这一名称。
BMP(Bitmap)是使用 Windows 自带的画笔来做成的一种图像数据形式。
JPEG(Joint Photographic Experts Group)是数码相机等常用的一种图像数据形式。
TIFF(Tag Image File Format)是一种通过在文件头中包含“标签”就能够显示出数据性质的图像数据形式。
GIF(Graphics Interchange Format)是由美国 CompuServe 开发的一种数据格式。这种格式要求色数不超过 256 色。
数码相机中经常用到的 JPEG 格式文件,有 3 种压缩方式。
(1)把构成图像的点阵的颜色信息由 RGB(红色、绿色、蓝色)形式转化成 YCbCr(亮度、蓝色色度、红色色度)形式。人眼对亮度很敏感,但对颜色的变化却有些迟钝。因此,人眼比较敏感的亮度 Y 就是一个很重要的参数,而表示颜色的 Cb、Cr 则没有那么重要。于是我们就可以通过减少 Cb 和 Cr 的信息间距来缩小图像数据的大小。
(2)将每个点的色素变化看作是波形的信号变化,进行傅里叶变换。
傅里叶变换是指将波形按照频率分量进行分解。照片等图像文件的特点是低频率(柔和的颜色变化)的部分较多,高频率(强烈的的颜色变化)的部分较少。因此,这里我们就可以把高频率的部分剪切掉。这样一来,图像数据也就会缩小。虽然剪切掉了高频率部分,但人眼分辨不出什么差别。不过,如果是用 Windows画笔描绘的简单图形,其中颜色变化强烈的部分就会出现模糊现象。大家不妨使用 Windows 画笔做一个圆形或者四方形的图形,并将其保存成 JPEG 格式。然后再打开这个 JPEG 文件,你就会发现颜色变化强烈的部分变模糊了。
(3)最后,将已经瘦身的图像数据通过哈夫曼算法进行压缩。
这样就可以使图像数据进一步缩小。
运行环境
程序(本地代码)的运行环境 = 操作系统 + 硬件
机器语言的程序称为本地代码(native code)。
CPU 负责解析并运行从源代码编译而来的本地代码(机器语言代码)。
CPU 能直接解析并运行的不是源代码而是本地代码的程序。
根据不同的运行环境来重新调整程序,一般也称为“移植” porting。
PDA(Personal Digital Assistant)是指可以放入手提包中的小型手持计算机。也称为“手持设备”。
程序的运行环境中,存在着名为 BIOS(Basic Input/Output System)的系统。
BIOS 存储在 ROM 中,是预先内置在计算机主机内部的程序。
BIOS 除了键盘、磁盘、显卡等基本控制程序外,还有启动“引导程序”的功能。引导程序是存储在启动驱动器起始区域的小程序。操作系统的启动驱动器一般是硬盘,不过有时也可以是 CD-ROM 或软盘。
开机后,BIOS 会确认硬件是否正常运行,没有问题的话就会启动引导程序。引导程序的功能是把在硬盘等记录的 OS 加载到内存中运行。虽然启动应用是 OS 的功能,但 OS 并不能自己启动自己,而是通过引导程序来启动。
Bootstrap 的原意是指靴子上部的“拔靴带”。
BIOS(Basic Input Outpu System)位于计算机主板或扩张板卡上内置的 ROM 中,里面记录了用来控制外围设备的程序和数据。
编译器:源文件 -> 可执行文件
消息框是一个为了显示短消息而出现的小窗口。
源代码 source code是用某种编程语言编写的程序。源文件是保存源代码的文件。
Dump是指把文件的内容,每个字节用 2 位十六进制数来表示的方式。
本地代码的真面目是数值的罗列。
能够把 C 语言等高级编程语言编写的源代码转换成本地代码的程序称为编译器。
交叉编译器,它生成的是和运行环境中的 CPU 不同的 CPU 所使用的本地代码。
确定编译器种类的三个关键词:编程语言,操作系统,CPU类型。
链接是把多个目标文件结合,生成 1 个 EXE 文件的处理。链接器(linkage editor)是运行连接的程序就称为。
链接器会在 EXE 文件的开头,追加转换内存地址所需的必要信息。这个信息称为 再配置信息。
EXE 文件的再配置信息,就成为了变量和函数的相对地址。相对地址表示的是相对于基点地址的偏移量,也就是相对距离。
库文件指的是把多个目标文件集成保存到一个文件中的形式。
链接器指定库文件后,就会从中把需要的目标文件抽取出来,并同其他目标文件结合生成EXE 文件。
外部符号是指其他目标文件中的变量或函数。
错误消息“无法解析的外部符号”表示的是无法找到记
述着目的变量及函数的目标文件,因而无法进行链接的意思。
不是通过源代码形式而是通过库文件形式和编译器一起提供的。这样的函数称为标准函数。
Windows 中,API 的目标文件,并不是存储在通常的库文件中,而是存储在名为 DLL(Dynamic Link Library) 文件的特殊库文件中。
DLL 文件是程序运行时动态结合的文件。
存储着目标文件的实体,并直接和 EXE 文件结合的库文件形式称为静态链接库。
#include <windows.h>
#include <stdio.h>
// 消息框的标题
char* title = "示例程序 1";
// 返回两个参数的平均值的函数
double Average(double a, double b) {
return (a + b) / 2;
}
// 程序运行启始位置的函数
int WINAPI WinMain(HINSTANCE h, HINSTANCE d, LPSTR s, int m)
{
double ave; // 保存平均值的变量
char buff[80]; // 保存字符串的变量
// 求解 123,456 的平均值
ave = Average(123, 456);
// 编写显示在消息框中的字符串
sprintf(buff, " 平均值 = %f", ave);
// 打开消息框
MessageBox(NULL, buff, title, MB_OK);
return 0;
}
程序加载时会生成栈和堆。
栈是用来存储函数内部临时使用的变量(局部变量),以及函数调用时所用的参数的内存区域。
堆是用来存储程序运行时的任意数据及对象的内存领域(内存中的程序,就是由用于变量的内存空间、用于函数的内存空间、用于栈的内存空间、用于堆的内存空间这 4 部分构成的)。
不管是什么程序,程序的内容都是由处理和数据构成的。大多数编程语言都是用函数来表示处理、用变量来表示数据。
Q :编译器和解释器有什么不同?
A :编译器是在运行前对所有源代码进行解释处理的。而解释器则是在运行时对源代码的内容一行一行地进行解释处理的。
Q :“分割编译”指的是什么?
A :将整个程序分为多个源代码来编写,然后分别进行编译,最后链接成一个 EXE 文件。这样每个源代码都相对变短,便于程序管理。
Q :“叠加链接”这个术语指的是什么?
A :将不会同时执行的函数,交替加载到同一个地址中运行。通过使用“叠加链接器”这一特殊的链接器即可实现。在计算机中配置的内存容量不多的 MS-DOS 时代,经常使用叠加链接。
Build = Compile 编译器 + Link 链接
操作系统
操作系统(operating system)是指管理和控制计算机硬件与软件资源的计算机程序。
操作系统(Operating System)也称为基础软件。操作系统是计算机运行时不可或缺的控制程序,以及在控制程序下运转的为其他软件运行提供操作环境的软件的统称。另外,在操作系统上运行的应用也称为“应用程序”。
具有加载和运行功能的监控程序,这就是操作系统的原型。
计算机中都安装有保存日期和时间的实时时钟(Real-time clock)。
应用程序经过 OS 间接地控制硬件。
移植性指的是同样的程序在不同操作系统下运行时需要花费的时间等,费时越少说明移植性越好。
文件是操作系统对磁盘媒介空间的抽象化。
Windows 操作系统的主要特征:
(1)32 位操作系统(也有 64 位版本)
(2)通过 API 函数集来提供系统调用
(3)提供采用了图形用户界面的用户界面
(4)通过 WYSIWYGA实现打印输出
(5)提供多任务功能
(6)提供网络功能及数据库功能
(7)通过即插即用实现设备驱动的自动设定
WYSIWYG 是 What You See Is What You Get 的略写。意思是,显示器上显示的文本及图形等(What You See),是(Is)可以原样输出到打印机上打印(What You Get)的。
Windows 是通过名为 API 的函数集来提供系统调用的。
API(ApplicationProgrammingInterface,应用程序接口)是联系作成应用的程序员和操作系统之间的接口。
32 位版 Windows API 也称为 Win32 API
GUI(Graphical User Interface,图形用户界面)
GUI,用的时候是天堂,做的时候是地狱。
多任务指的是同时运行多个程序的功能。Windows 是通过时钟分割技术来实现多任务功能的。
即插即用(Plug-and-Play)指的是新的设备连接(Plug)后立刻就可以使用(Play)的机制。新的设备连接到计算机后,系统就会自动安装和设定用来控制该设备的设备驱动程序。
NIC(Network Interface Card)是计算机连接网络(LAN)时使用的设备。也称为网卡或者 LAN 卡。
程序是操作系统、中间件、应用等所有软件的统称。
汇编语言
本地代码的指令中,表示其功能的英语缩写助记符
汇编语言的源代码转换成本地代码的方式称为汇编。负责转换工作的程序称为汇编器
本地代码转换成汇编语言的源代码的方式称为反汇编。持有该功能的逆变换程序称为反汇编程序。逆变换这一处理本身称为反汇编
汇编语言的源文件的扩展名,通常是 .asm 格式
汇编语言程序中的段定义指的是构成程序的命令和数据的集合组
汇编语言的跳转指令,将程序流程跳转到其他地址时需要用到该指令
汇编语言的源代码和本地代码是一一对应的。
汇编语言的源代码,是由转换成本地代码的指令(操作码)和针对汇编器的伪指令构成的。
伪指令负责把程序的构造及汇编的方法指示给汇编器(转换程序)。不过伪指令本身是无法汇编转换成本地代码的。
由伪指令 segment 和 ends 围起来的部分,是给构成程序的命令和数据的集合体加上一个名字而得到的,称为段定义。
段定义的英文表达 segment 具有“区域”的意思。在程序中,段定义指的是命令和数据等程序的集合体的意思。一个程序由多个段定义构成。
DATA segment 和 _DATA ends、_BSS segment 和 _BSS ends、_TEXT segment 和 _TEXT ends,这些都是表示各段定义范围的伪指令。
段定义(segment)是用来区分或者划定范围区域的意思。
汇编语言的 segment 伪指令表示段定义的起始,ends 伪指令表示段定义的结束。
段定义是一个连续的内存空间。group 指的是将源代码中不同的段定义在本地代码程序中整合为一个。
标签表示的是相对于段定义起始位置的位置。
在汇编语言中,1 行表示对 CPU 的一个指令。汇编语言指令的语法结构是操作码 + 操作数(也存在只有操作码没有操作数的指令)。
操作码表示的是指令动作,操作数表示的是指令对象。操作码和操作数罗列在一起的语法,就是一个英文的指令文本。能够使用何种形式的操作码,是由 CPU 的种类决定的。
在汇编语言中,类似于 mov 这样的指令称为“操作码”(opcode),作为指令对象的内存地址及寄存器称为“操作数”(operand)。被转换成 CPU 可以直接解析运行的二进制的操作码和操作数就是本地代码。
寄存器是 CPU 中的存储区域。不过,寄存器并不仅仅具有存储指令和数据的功能,也有运算功能。
x86 系列 CPU 的寄存器的主要种类角色如表 10-2 所示。
寄存器的名称会通过汇编语言的源代码指定给操作数。内存中的存储区域是用地址编号来区分的。CPU 内的寄存器是用 eax 及 ebx 这些名称来区分的。此外,CPU 内部也有程序员无法直接操作的寄存器。
例如,表示运算结果正负及溢出状态的标志寄存器及操作系统专用的寄存器等,都无法通过程序员编写的程序直接进行操作。
32 位 CPU 寄存器的名称中的 e,有扩展(extended)的意思。
x86 系列 CPU 的主要寄存器:
寄存器名 | 名称 | 主要功能 |
---|---|---|
eax | 累加寄存器 | 运算 |
ebx | 基址寄存器 | 存储内存地址 |
ecx | 计数寄存器 | 计算循环次数 |
edx | 数据寄存器 | 存储数据 |
esi | 源地址寄存器 | 存储数据发送源的内存地址 |
edi | 目标基址寄存器 | 存储数据发送目标的内存地址 |
ebp | 扩展基址指针寄存器 | 存储数据存储领域基点的内存地址 |
esp | 扩展栈指针寄存器 | 存储栈中最高位数据的内存地址 |
程序运行时,会在内存上申请分配一个称为栈的数据空间。
数据在存储时是从内存的下层(大的地址编号)逐渐往上层(小的地址编号)累积,读出时则是按照从上往下的顺利进行(图 10-3)的。
最优化功能是编译器在本地代码上费尽功夫实现的,其目的是让编译后的程序运行速度更快、文件更小。
函数的参数是通过栈来传递,返回值是通过寄存器来返回的。
局部变量只是在函数处理运行期间临时存储在寄存器和栈上。
在汇编语言的源代码中,循环是通过比较指令(cmp)和跳转指令(jl)来实现的。
jl,是 jump on less than(小于的话就跳转)的。
比较结果小时跳转的 jle(jump on less or equal)、 大 时 跳 转 的 jge(jump on greater or equal)、不管结果怎样都无条件跳转的 jmp
汇编语言是对 CPU 的实际运行进行直接描述的低级编程语言,C 语言是用与人类的感觉相近的表现来描述的高级编程语言
线程是操作系统分配给 CPU 的最小运行单位。
源代码的一个函数就相当于一个线程。多线程处理指的是在一个程序中同时运行多个函数的意思。
可以采用以函数或 C 语言源代码的行为单位来禁止线程切换的锁定方法。通过锁定,在特定范围内的处理完成之前,处理不会被切换到其他函数中。
硬件控制方法
DMA = Direct Memory Access 直接内存访问:指的是不经过 CPU 中介处理,外围设备直接同计算机的主内存进行数据传输。
Window 控制硬件时借助的是输入输出指令。其中具有代表性的两个输入输出指令就是 IN 和 OUT。这些指令也是汇编语言的助记符。
IN 指令通过指定端口号的端口输入数据,并将其存储在 CPU 内部的寄存器中。
OUT 指令则是把 CPU 寄存器中存储的数据,输出到指定端口号的端口。
IN 寄存器名,端口号 // 输入数据
OUT 端口号,寄存器名 // 输出数据
计算机主机中,附带了用来连接显示器及键盘等外围设备的连接器。而各连接器的内部,都连接有用来交换计算机主机同外围设备之间电流特性的 IC。这些 IC,统称为 I/O 控制器。
I/O 是 Input/Output 的缩写。显示器、键盘等外围设备都有各自专用的 I/O 控制器。I/O 控制器中有用于临时保存输入输出数据的内存。这个内存就是 端口。
I/O 控制器内部的内存,也称为寄存器。虽然都是寄存器,但它和 CPU 内部的寄存器在功能上是不同的。
CPU 内部的寄存器是用来进行数据运算处理的,而 I/O 寄存器则主要是用来临时存储数据的。
一个 I/O 控制器既可以控制一个外围设备,也可以控制多个外围设备。各端口之间通过端口号进行区分。端口号也称为 I/O 地址。
以端口为桥梁来实现 CPU 和外围设备之间的数据传递。
在大部分 C 语言的处理(编译器的种类)中,只要使用 _asm{ 和 } 括起来,就可以在其中记述助记符。
也就是说,这样就可以编写 C 语言和汇编语言混合的源代码。
// 利用 IN/OUT 指令来控制蜂鸣器
void main(){
// 计数器
int i;
// 蜂鸣器发声
_asm {
IN EAX, 61H
OR EAX, 03H
OUT 61H, EAX
}
// 等待一段时间
for (i = 0; i < 1000000 ; i++) ;
// 蜂鸣器停止发声
_asm {
IN EAX, 61H
AND EAX, 0FCH
OUT 61H, EAX
}
}
IRQ(Interrupt Request)是中断请求。
IRQ 是用来暂停当前正在运行的程序,并跳转到其他程序运行的必要机制。该机制称为中断处理。
实施中断请求的是连接外围设备的 I/O 控制器,负责实施中断处理程序的是 CPU。为了进行区分,外围设备的中断请求会使用不同于 I/O 端口的其他编号,该编号称为中断编号。
操作系统及 BIOS 则会提供响应中断编号的中断处理程序。
可以在 I/O 控制器和 CPU 中间加入名为中断控制器的 IC 来进行缓冲。中断控制器会把从多个外围设备发出的中断请求有序地传递给 CPU。
DMA(Direct Memory Access)可以实现短时间内传送大量数据。
DMA 是指在不通过 CPU 的情况下,外围设备直接和主内存进行数据传送。
资源是计算机具备的有限资源的统称。端口号、IRQ、DMA 等可以指定的数值范围都是有限的,因此它们也是资源的一种。
I/O 端口号、IRQ、DMA 通道可以说是识别外围设备的 3 点组合。
不过,IRQ 和 DMA 通道并不是所有的外围设备都必须具备的。计算机主机通过软件控制硬件时所需要的信息的最低限,是外围设备的 I/O 端口号。
显示器显示文字及图形的机制。
显示器中显示的信息一直存储在某内存中。该内存称为 VRAM(Video RAM)。
在程序中,只要往 VRAM 中写入数据,该数据就会在显示器中显示出来。
实现该功能的程序,是由操作系统或 BIOS 提供,并借助中断来进行处理的。
在现在的计算机中,显卡等专用硬件中一般都配置有与主内存相独立的 VRAM 和 GPU(Graphics Processing Unit,图形处理器,也称为图形芯片)。
用软件来控制硬件听起来好像很难,但实际上只是利用输入输出指令同外围设备进行输入输出的处理而已。
中断处理是根据需要来使用的选项功能,DMA 则直接交给对应的外围设备即可。
计算机能处理的事情,始终只是对输入的数据进行运算,并把结果输出。不管程序内容是什么,最终都是数据的输入输出和运算。
计算机“思考”
程序的使用目的大体可以划分为两类。一类是大家作为工具来使用的程序。另外一个使用目的是用程序来代替执行人类的思考过程。
微计算机是微型计算机的简称。通常是指专门用来控制家电等的小型计算机。
随机数指的是随机出现的没有规律的数值。
通常所说的随机数指的是统一随机数。统一随机数指的是在一定数值范围内各数出现频率相同的随机数形式。C 语言中的 rand() 函数的返回值就是统一随机数。
计算机模拟指的是利用计算机模拟实际试验的方式。经常被用于建筑物的耐震实验等实际难以进行的实验中。使用随机数的计算机模拟有时也称为“蒙特卡洛法”,来源于因赌博而闻名的城市──蒙特卡洛。
人类的日常判断通常是根据直觉和经验做出的。
人类还有一个思考方式。思考方式是思考方法的节奏。
所谓编程,就是把程序员的思考方式用编程语言的语法结构表示出来,然后再传递给计算机运行。
自己吓唬自己是最可怕的事情。
C 语言的关键字(按英文字母排序):
auto 声明自动变量
break 跳出当前循环
case 开关语句分支
char 声明字符型变量或函数
const 声明只读变量
continue 结束当前循环,开始下一轮循环
default 开关语句中的“其它”分支
do 循环语句的循环体
double 声明双精度变量或函数
else 条件语句否定分支(与 if 连用)
enum 声明枚举类型
extern 声明变量是在其它文件中声明
float 声明浮点型变量或函数
for 一种循环语句
goto 无条件跳转语句
if 条件语句
int 声明整型变量或函数
long 声明长整型变量或函数
register 声明寄存器变量
return 子程序返回语句(可以带参数,也可不带参数)循环条件
short 声明短整型变量或函数
signed 声明有符号类型变量或函数
sizeof 计算数据类型长度
static 声明静态变量
struct 声明结构体变量或函数
switch 用于开关语句
typedef 用以给数据类型取别名
union 声明共用数据类型
unsigned 声明无符号类型变量或函数
void 声明函数无返回值或无参数,声明无类型指针
volatile 说明变量在程序执行中可被隐含地改变
while 循环语句的循环条件