第一部分
前 言
By Chenyi
眼前这本书充分体现了作者的所思、所想、所感,他用自己独特的眼光审视着计算机技术的世界,也用自己独特的思维逻辑对技术进行解读,并用自己特有的,呵呵,偶尔带有“四个逗号=一个逗号”这样的语言风格,进行着自己的诠释。创新是一种美,独立思考也是:)
学习是一件因人而异的事情,因为每个人的生活经历、教育背景、年龄、认知模型等等,都是不尽相同的,也就是每个人所处的“维度”不同,而作者有一种“建立更高层抽象的能力”,用一种特有的方法尝试着给大家建立一个学习计算机的、相对高层的构架,这样,可以在一定程度上突破个人的“维度”,使大家从与周围事物建立联系开始,一步一步的走向计算机的世界。不识庐山真面目,只缘身在此山中。确实的,在学习技术的过程中,横看成岭侧成峰,远近高低各不同,但是作者却尽力想让这高低或是远近都不同的山峰,能在我们面前呈现出一种规律、共性来,这是难能可贵的,因为这个架构的过程对思维的要求是比较高的:)
哲语有云,动身的时候到了,有的人去生,有的人去死,只有上帝知道,于是这个问题被回归到“ To Be ? OrNot To Be ”的问题,是生,是死,只有上帝知道。
但是,人类对真理的探索和对知识的追求,却从来没有因为“生死”的维度而停止过,是的,一颗崇尚真理、探寻真理的海洋之心,将从来不会因为泰坦尼克号的沉沉而消沉,它将永远绽放在人们的心中,激励着我们向更广阔、更深髓的世界,一路前行、风雨无阻:)
在这个意义上,鼓励作者的写作和思路,也是对我们自身追寻真理的一种鼓励、一种回路。是为一点小感想:)与作者分享!!
By Minlearn
对思想的认识和界定是重要的!!因为我们需要一个知识体系才能不致于困惑!!(而身处编程界,纷繁复杂的术语和概念足以让一个初学者却步)
我抓住了哪些转瞬就在我脑中消失的思想,,因为它们远比一切成书的东西都让我感到它的珍贵!而更玄的是,他们竟然真的能够被文字描述出来!!这整本书就是小说式的教学。它力求呈现出一个精致化了的术语集。以使初学者能真正理解至关重要的那些概念。
正如Chenyi所说,每个人都是某个维度上的人,有他自己的年龄和认知,具体到某个历史时刻,我们的人生阅历已然被格定,而这决定了你接受新事物的能力和眼界,人生在世,已经不可能脱离某种信念(也异或某种阻力和障碍)而活,当我们开始学习编程,我们永远都是用外行的眼光去看待某样东西,而当你占在巨人的肩膀上成为一个专家之后,你就需要用全局的眼光去看待曾经陌生的知识,此时你不再是个学习者,而会批评产生你自己的认知,但那毕竟是要过的第二道槛,而初学者就是那些连第一道槛都难以过去的群体。
这其中最大的拦路虎就是对术语的理解,很多书并不切合初学者的实际,从他们的角度呈现一条清楚可见的理解路线,而只是一些大部头衍生下的反复抄袭品。
给你一个术语或道理,这个道理有什么用?没用,是的,因为要给你一个情景,你才能理解它,仅仅让你去学一个知识,而知识和众多其它知识之间相似而微有不同,如果不给出它被产生时的历史和它所处的架构(这本书不但给你思想,而且给你对应的细节),那么我们就会迅速迷惑,更遑论运用它,因为我们不是泛化主义者,形而上学者(但是的确存在超前主义学说,只是为了创立一种学说,后来才慢慢与实践相结合),我们需要一种与自身相联系点去理解它,我们只是生活的人,我们不是高高在上的学院派高手。
一个高手必定是与常人有不同的思想级深层的东西和他自己特有的体会,因为他也走过初学者才走过来的路,可是往往人们都忘了归纳那些至关重要的经验,那会是什么经验呢,那些是不会出现在任何描述具体技术细节的书里的思想级的东西,那么这本书尝试的正是记录那些秘诀,如果真的想当高手,请你不要错过这本书里任何一个字眼!!如果你是高手,这本书一定与你内心深处的某些想法偶合。
本书过后,再辅于其它教科书(比如你手头上的一本C++教材,本书后面列举了一些与本书能很好答配的推荐参考书)你应该会具备基本的编程能力和编程理解能力。本书前半部分是对思想和认知的导论,后半部分注定实践和技能能力的形成。
知识是事物之间的联系,那么实践就是强化或深入这些联系的方法,我常想,到底是什么重要,是认知还是技能,人们普遍认为实践应在任何情况下都高于认识,事实是:可能有技能但是没有认知,但却不可能有认知但没有技能,就拿学习英语来说吧,看英语报纸也是一种实践,因为它也能够加强你实际使用英语的能力,(我不是在模糊这二者之间的区别,我只是企图站在这二者之上求得一种更泛化的认识),实践不过更侧重动手能力而已民,而认知跟它并不矛盾,知识的获得与能否运用知识本身无必然因果,拥有足够的知识,再加上泛型的思维,,你就会快速得以实践,一切都是一种格物致知的过程,只有格物至知,先格物,认识到了一定程序后就会产生对事物本质的认识,也可先认识事物本质再在指导下去发展技能,但是认知可以直接传递给你(至此只是一个你所能想象得到的浅层和大概,而且除非实践,这个大概形象你也不知道它到底是正确的还是错误的,更深层的你想象不到的抽象以及关于这些认识的正确性要求实践),相比之下一本书不可能传递很多实践的东西。本书前一部分正是力求让初学者完成从认知到实践的有效过渡。
所以说实践和认知都是重要的,没有谁比谁更重要的说法,然而对于初学者来说浅层认知的重要性要高于实践,一开始就有一个好的思想和基础显然可以为未来的实践扫清障碍,这是因为学习是一个层次上升阶段,在拥有一定知识后,理解基于这些知识之上的更高层知识会很快,, 即掌握了基础再加上一定勤奋的博物广识,知识量是几何级上升的,因此一种很好的学习方法是,学习应该先吞,(在一定知识量的前提下尽可量地博物广识,即使看不懂也要浏览完,以获得浅层的认知继续下一步学习),这是学习中自然而痛苦的过程。(不是提倡光谈和光看理论,而是把理论整理成一个架构也是一项重要的工作,不是不能直接把这个认知传递给你,而是需要再找一个与你的结合点来让你认识它,因此它是一本同时讲解到认知与实践的书,
不是提倡导光谈理论,而是如果事先有理论的指导,那么学习中就会少走很多弯路,学习中最怕不能理解细节,更怕以为细节就是一切,所谓一叶屏目不见泰山,更有人把学习语言作为编程的终极目标,而如果事先有人给你指导,你就会少走很多弯路)
在学习方法上面,有一个问题是关于细节和思想的。
我们鼓励在实践基础上去学习,也提倡速成,但大多数人显然不会拥有正规的实践教育,我认为学习不应该提倡逐步深入,人的生命有限,染启超在渡日的般上一夜之间学会日语,这就是说他掌握了思想,细节的东西永远是后来的,只要思想是重要的,(了解足够多的细节才能泛思,,在学习编程中,除了一些对至关重要概念集的理解之外,,从来都不是大思想决定一切,而只是小细节,这就要求你作很多的实践)
掌握了思想和基础后,每天写小程序,编程能力就会日渐提高,而当你写过和分析过很多程序之后,你就会具备一眼看出的本事,过程的最后你发现自己蛹变蝶飞了
学习应首先理解框架(这是泛读),然后是细节(这就是对某些内容的精读),就好像在一个大型应用中,编译跟解释并不会走二个极端一样(低层用编译码,而高层用脚本),学习往往是混合了这二个过程的过程,,,矛盾和老子的不可绝对在这里起作用
所以说思想和基础永远是重要的(人月神话的作者固然精通很多细节,但是他写出来的却是一本思想书),,知识和思想自然是越多越好(泛读可以无限进行,花再多人年都无碍,人年是人月神话里面的概念),但是有一些知识不必深入(精读却需限于自己的开发领域),但一定要知其然
本书主体中的二部分就是认知和实践,思想和细节的结合,所以你要做的就是在认识的基础上作大量实践。这就是我在前言的后半部分推荐给你的看书方法。
如果说一些知识仅仅知其然就够了的话(仅仅是不致于迷惑和建立知识结构),那么有一些知识却是要精通的,因为不但要知其然而且要实际拿来应用
要成为某领域能实际胜任某份工作的程序员,就要做到精通四个“Idioms”(注意这是精通)
1. 你要用到的语言和IDE的“Idioms”(一门语言,一种开发库)---编程首先就是会用一门语言和它的库
2. 数据上的”Idioms”(数据结构-数据的内存模式,数据库-数据的外存模式)---编程第一个就是数据,想起DOS下的编程了吗,一是数据,二是代码
3. 设计上的”Idioms”(面向对象,设计模式)-----编程第二个就是代码或代码框架
4. 以上三条都是前提,那么这第四条就是最终的你要实际涉入的业务领域的”Idioms”---编程最终是为了为这个领域服务
以上四条是主干(最好按1-4的顺序精读),而其它的都是支节。比如工具的使用啊,XML啊,UML啊,XP方法啊,ANT部署发布知识啊等等
对于计算机专业来说,为什么也才那么几门课程(高数线代离散,编译原理,C与算法,Java),,因为这些学科是最重要的(真正掌握了这些基础,你会发现再多后面的技术用语及其背景都是支节),这就相当于前面提出的四个Idioms
对语言细节的学习和深刻理解永远都是学习编程的重头戏,但决不是一切,比如拿编程语言来说,只要越过语言的表达这一层,我们才能用语言表达和理解事物(语言跟你要说的话就像用C++语言去表达一个算法,方案领域跟应用领域的对应,就像穿鞋去上海, 穿上鞋只是开始,真正你要去的目标-上海还远着呢),就像口才,一个好口才的人说话时绝对不会想到措词,因为语言已经成为一种意象,只要把一样东西思想化,才能超越这个东西而去想到别的东西而长足发展,比如面向对象,这本书将帮你解释为什么面向对象是一种科学的机制,解释的过后你甚至会觉得这是一种本来就该存在的很亲切的机制,只要超越了面向对象我们编程时,再加上一定设计模式,才能真正不会一动手编程就考虑什么是面向对象之类。。(而这些,好像都是一个高手所能做的事了。)。
编程时碰到的信息量永远是巨大的,有生之年我们不可能掌握这些信息的来龙去脉,对于程序员来说,提供一个关于它的编程参考文档可以说是掌握了此信息,因为这个文档就是这个信息的大概,实际上我们编程大部分情况下都只是用第三方的代码库来编程,这个信息用于编程所需的全部东西,对于编程来说只要掌握这些东西就行),换句话说,一些知识如果不能理解就得先放(这本书并不适合于赶考使用), 在这个信息的社会,至于信息,是撞事学事!一个程序员并不全知全能,它只提取和了解事物对于编程方面的信息。对于事物的逻辑认识,只能在对它的编程中不断掌握它,抽象是惯穿这本书的重要的思想,维度也是,我们是从学习编程的眼光来组织这本书的。也是站在初学者的角度来解释诸多概念及其关系的。
问题随之而来,既然存在这个界限,又如何突破,否则这就是一个空谈
多走弯路,学习是认识事物间联系的过程,而记忆或实践是加强这个联系的过程,,能够认识到事物之间的联系,即便是自想的联系也可加深对事实的记忆(一个程序员有他自己的知识体系是重要的),这就是知识
一切东西,我们应该查本究源,深入其原子世界(任何一个术语都不会简单,有它自己产生的环境与其它知识的联系,但也正是因为这样,这也决定了它的有域性,任何知识只要放在它自己的领域内去理解才能更容易被理解),, 翻译过很多文章你就知道要措词,措词跟概念有关,二个稍微相差不大的措词都会让读者摸不头脑或让他们恍然大悟。
我们高中做到了英语的相似名词不同分析,本书也打算在一定程序上这样做(虽然计算机技术领域一个概念可以自成一书这种现实不允许我们这样做),咬文嚼字在这里起作用,,在某些情况下,它是一种好习惯!
然而千万不要走入另外一种极端, ,知识用词和技术用语没有一个标准,比如方法和函数指的是同一个东西
什么是线性(一次就是线性),什么是离散(离散了的量),这都是仁者见伍,智者见,但人们对此的理解都不会差到那里去,并且也不会影响后来的学习,这里有一个描述或形式的概念,相信大家都还记得初中学过的集合,是描述性概念,但集合其实还有一个形式概念,给定了形式就可以框死
而且,要知道,即使是《虚拟机的原理与设计》这本书的作者也会对别人书里的进程概念感到不解。
我注意到程员序考试中多了一项标准化,的确,知识的传达也需进入标准化时代了
最后,如果说任何行为都是功利的,那么我写这本书的目的只为博你一笑。
书中错误再所难免,望不吝赐教!!
l 别怀疑,这正是一本同时可作为入门和进阶级的书(更偏重入门)!然而真正的高手和真正的初学者都将从中有所得。
l 你还在为学不懂大量术语而烦恼吗?如果你真有这种体会,那么你可能先要看这本书再看你正在看的C++的书,因为你仅仅缺少一根主线, 而它是能让你少走很多弯路的拐棍
l 对架构的学习才是真正的学习,知识也有它的架构,然而在这本书内有架构也有细节(高手固然知道细节,然而高手也有精神空洞,因为你还需要懂得一些细节之外的架构级的东西)!
l NotWar3的从零到尾的实现,让你知道其实你一个人就可以做出类War3的游戏!!(本书作者也自称是一个菜鸟,但是这个程序的确是他自己写的)
导 读
任何语言都是有门槛的
C用最初级的封装了汇编的逻辑写应用,这也就是C代码看起来难的原因,如果你看过位操作(比如oopc实现的RTTI),看过用C表达的数据结构,就会发现,有时看出来样子普通的一堆语句,你根本不知道它想表达什么上下文逻辑(因为C代码本身跟现实问题走了二个极端,你看懂了代码却看不明白代码后面的东西,这是因为有设计在作梗,而C跟设计和现实问题走了二个极端),除非你真一开始就明白它想写什么(有文档的情况下),但Java这样的语言,能够整体上看起来是一个一个的类,显得意义明了,但实际上语言越接近应用问题反而代码看起来更复杂,,因为现实生活是很难的你根本做不到绝对靠近除非你为每一个问题写一个dsl(C表达的向系统问题接近和Java表达的向现实靠近各有各的难处,作为一门工业语言,要求它看起来便于程序员理解和复用,Java这方面是做得不错的而C肯定只是专家语言),一堆有机类有时反而难于让人看出它想表达什么,而且另外一方面,类里同也是函数,也是Java的语句逻辑而不是封装上的类逻辑,这些语句逻辑,同样用Java中的库来形成,Java的库是重新经过设过的,相比C语言,比如它规范了流的概念,Java的OO和规范的库是人们说Java比其它语言易的二个方面。。
但是虽然熟悉编程的人可以拿来用,但是对于没有编程经验的人来说,它照样跟C一样难。
因此JAVA的所谓易,是相对用过C的这样的熟悉编程者来说的。至少使用JAVA,我们照样得学好跟C一样的数据结构知识。。
看不懂一套源程序,主要是
1)你不知道普通的语句是体现什么样的数据结构
2)你不知道普通的语句是体现什么样的算法
3).........抽象惯用法
4)。。。。。如何向现实问题靠近抽象并设计的
5)现实问题的复杂性,跟语言逻辑的简单性,非dsl之间的矛盾(语言从来被设计成通用的)..
因此要学好一门语言解决问题,不但要学精语言的语法和库,而且学习的重点还就在于:
数据结构和算法,现实问题,,抽象和设计。。。
什么是语言级和语言外要学习的(数据结构与代码结构)
设计最终要被体会到源程序,如果把设计作为整个软工过程,那么源程序是这个工程最好的结果最终证明,(参见《源程序就是设计》一文,你可以google得到它)
我认为这样的说法是对的,因为它综合了我在下面要谈到的1,2二个过程。(但因为它没有显式提到下面我列出的二个过程,所以我认为该文在一定程序上是一篇含糊其词的文章)
1是脱离了语言的那些映射,即人们通常说到的设计一词的意义(请参照我的《什么是设计》一文,这里的设计实际上是指大设计,指领域抽象,语言选择,这些东西,包括数据结构),2是结合了语言的实现映射。即人们通常说到的实现,不过人们通常把1作为架构师的工作,而把2作为程序员的工作而已。如果架构师的工作深入到类的类部,深入到详细设计,那么他实际上担当了一部分程序员的工作。但在人类的工作中,2是受1控制的,
这里面其实有一个代码抽象模式和数据抽象模式的区别。
类实际上是一种数据抽象,而不是一种数据结构,,因为它将代码抽象为一个一个的“数据模式”,即将C++这样的通用语言增加DSL词汇,让它成为DSL,可以表达class cat,class pig,猪猫,诸如这样的领域词汇,所以类是一种数据(把词汇抽象为语言的一级first class数据,即UDT,ADT这里面D的意义)抽象模式,也就是代码模式,而数据结构学是一种实现模式,而不是代码模式。
数据结构学与代码结构学的区别,是解决问题的问题和解决语言映射问题的区别,两者在不同抽象层次,这就是为什么数据结构可以用任何语言可以用基本流程实现也可以C++的类来实现,因为数据结构学跟它如何用一种代码结构来抽象是没有直接关联的,前者是如何解决问题的抽象(是一种脱离了语言的映射,即我在1中谈到的设计),后者是代码问题(如何面向用了类的可复用目的来进行对具体语言的映射,即我在2中谈到的实现)。
在编程的实现领域,从来最终都是过程编程即Core C的那些内核逻辑〔类体里面也是〕,所以,用了类,只是将面向过程抽象到了一个更好被复用的问题,并没有将如何实现这层抽象到程序员不需要理会,所以对于不懂C的人来说,即使它能很好理解OO,也做不了什么程序〔类只是将实现套了一壳,从而将面向对象层次的复用维持在这壳外,壳的里面却不行,照样是过程编程〕,OO的强大只是指它类外的那些代码抽象模式。OO提供的最本质的意义和作用有二,1,将C++这样的通用语言“在类层次”变成为DSL,2,正是因为1的作用在先,所以普通个人也可以开发复杂的软件系统。
也是C程序员的能力更多在前者(数据结构),而数据类型属于后者,设计模式,面向对象都是后者,是C++程序员或架构师的事。
对于2,即实现。跟具体语言有关。下面举C和C++为例。
遗憾的是,C++只是对C的增强而非替代,如果他离开了C,就只能有类的代码模式的复用能力,却无法保留C的强大而直接的实现能力(如果写数据结构这样的东西都要强制用到类,那么除非有必要为复用作目的,否则没有用C++的必要。),所以一个C++程序员(假设他用了OO来实现数据结构)既是一个实现者,也是一个设计者。因为它既抽象了如何能被解决的问题,又抽象了如何能被复用的代码。
程序员对于算法,数据结构,数学实现问题这些细节的实现问题把握最重要,而不仅仅是语言能力设计,代码抽象能力,如果有架构师的工作在先,C的程序员仅仅需要提供函数过程模块,(极度求接口化和求极度模块化,设计是需求驱动的,接口是要提供的功能驱动的,都是不必要的那是架构师的工作)
什么是语言级要学习的
什么是编程要学的。首先给出一张图。图中描述了编程知识结构。
就学习一门语言比如C来说。
综观C语言的语句形式,就只有编译原理后期翻译的那些语句形式了,,仅仅从语句形式上来看是这样的。。
计算机能做的事,就是CPU的取指令,译指令,执行指令,从内存中取数,CPU用逻辑器和运算器运算,,中断处理例程,IO设备的功能,
这些是计算机能做的全部事情,由CPU统一控制,,因为这是所有硬件资源能做的事情。。计算机后来所有的软件逻辑包括OS的所有的功能都由它决定。。
由OS生成调用这些如上硬件资源的策略。。
template是C++的一种高级语言机制,它建立在C++的类型机制上提供范型,但是它的语法及其古怪,跟C++那些其它的普通语言机制十分不相同,(由于语言是由语法定义的,因此我们称,类型,表达式,控制语句形式,赋值语句,这样的东西为语言的要素,打开任何一门关于程序语言教学的文章,我们都可以发现这一点。。字符串,IO,异常,标准库,,数组,与Windows的接口,这样的东西是语言的高级话题,和高级功能,不是语法级规定的,,比如可能是库提供的)
编程学习方法
只要学习C语言,计算机系统知识,语言实现原理,网络原理这些系统知识,才能从一个比较大的侧面去看待现实问题对于计算机的实现问题(也即编程问题),,只有这样,只有懂C,懂编译原理,懂计算机系统,懂网络,才能从一种大局的高度去看待并计划你的系统你的应用。。
要学习编程,我觉得C语言是起码要学的,即使是以后学LUA,RUBY这样的高阶语言,最好的途径还是先学C.
学习编程必定最后要涉及到系统逻辑,那么是首先学习上述的计算机专业课程的知识,还是先学语言呢,,,,我觉得是先学语言,,因为理论的知识在没有实践的前担下很难掌握,,而一开始就学习语言(我这里只指C语言)是最好的办法,,,因为在学习的过程中,你需要一门语言来实践,,,验证各个小问题的语言实现,来掌握更多的知识
计算机学生专业课程本质讲解
RUBY跟C语言还是结合得蛮紧的,,RUBY在数据结构方面还是有C语言影子的,,人们说RUBY偏向于人,但是几乎所有的语言都脱离不了数据结构,,都脱离不了底层,,RUBY的OO只是指类的那一方面,,RUBY的IO,数据结构,跟其它语言是一样的,,,复杂,跟底层相关,,数据结构和底层有什么关系呢?内存地址是线性的啊,这就是数组,,我们的虚拟机是栈式机啊,,所以要堆栈,,我们的运行时把类对象分配到堆中,,,所以要堆,,这就是编程语言处理计算机,解释器本身的离散形式而导致的复杂性,,所有的语言包括RUBY都没有很好地用OO封装数据结构,STL是个例外,,但是无论理解OO的STL还是RUBY的数据结构,都是差不多要理解到底层,即数据结构的原理,每种数结的具体情况,,学习RUBY并不能让你省这个懒,,问题就出在这,,,要学好RUBY,C的数据结构方面还是要下点功夫的,,任何一门语言,语言库包括STL都没有自称它把数据结构简化到不需要明白任何具体数据结构的形式就可以拿它来进行编程的程度
? 其实计算机专业学生的那些课,,数结,C,操统,都是无比珍贵的东西 ,,学校设立这些课而不是C++,不是RUBY,,是因为那些才是可以解释后来一切的底层 ,,而并非一种舍本未未的作法..
语言就是处理三个东西之间的关系,平台,语言,要解决的问题(解决什么问题用什么语言最好),其中,汇编基础:解释了硬件平台,即CPU中内置了控制内存的模块,因此要涉及到寄存器,内存地址等,操作系统课程,如果说汇编基础解释了解硬件平台,那么这就是解决的软件平台的问题,而离散数学,,就是一切离散形式,计算机和程序语言环境,和语言本身都是本质上一些离散形式,比如图灵机就是程序模型,是个离散东东,在编译原理中体现就更明显了,比如函数语言实际上就是一种高次方程的离散,编译原理的本质是什么呢,,,如果说硬件和操作系统都是解释了平台,那么编译原理就解释了程序本身的本质,那么C语言课程呢,,这解释了硬件编程的一些方面(C+大量汇编的形式广泛用于硬件编程,驱动开发),,而且,C语言这门课程最最重要的意义还在于,它解释了一切后来的高级语言比如RUBY,比如JAVA,要学习到的跟底层相关的离散形式,,这是尤为珍贵的,比如进程,比如并发,比如异常,,比如数据结构,而数据结构中的"数据"二字永远是一个程序的中心因素,,从普通数值,字符串,数值到结构体到OO数据,体现了人们封装程序开发数据对象的复杂性的要求..而且这种发展是为了产生一种广泛深度的开发方法的,这导致了软工,JAVA就是这样一种好的语言.
应该如何从C的观点来看待你的编程语言比如RUBY跟操作系统之间的关系呢?一方面,C本身就是一门硬件编程语言和系统开发语言*(OS一般就用C来开发,很少用第三代语言比如C++,JAVA,RUBY),而且,C语言就是一切语言的基础,JAVA,RUBY都是用它写的 ,这导致了一些现实,,下面一一说来,C语言跟OS编写有关,是OS的直接宿主语言,,其它的比如RUBY,比如C++,比如JAVA,,是C的上层语言,学了C语言,,RUBY,JAVA,OO,都很简单 而且C语言是系统编程语言,是底硬件编程语言(embed c),,,是使用最多的语方,opengl能用JAVA开发吗,,不能,那会慢得要死,而且根本也不行,,,驱动程序能用JAVA吗,,那简单是笑话,,只有WEB开发,,这些不需要很实时的I/O,这些架在逻辑上的逻辑(TCP,HTTP,WWW,SOAP一层一层而来)不需要很强的反应,,才可以用JAVA,而且JAVA编程统一,OO复用强,,是软工理想语言,
一句话,C扩展RUBY简单,而RUBY调用C却需要BIND,,一句话,编程三个平台,1硬件,裸机,,用C好,,2配有OS的桌面,用C好,,用OO的C++也可,,,3,WEB,用JAVA好,用OO好
C语言一般用来作底层编程,比如那些靠近硬件层的,选用普通的C语言(C语言标准)可以在WINDOWS平台上开发控制底层的编程,而且还存在嵌入式C语言用来开发各种硬件编程,驱动,BSP(主板支持驱序),比如一些智能手机的操作系统开发等,其实C语言开发也就是一种范式,一种编程习惯,它是过程式命令编程范式的代表,世界上用得最大的编程语言不是JAVA,不是RUBY,不是VB,而是C,因为C用来作系统编程时,它可以提供较快的运行速度,接近底层的更好控制,实现C语言的编译器是一种将C语言代码直接编译成本地码的工具,不存在任何逻辑中间层次或解释程序(比如虚拟机)因此运行速度很快而且,C语言提供的指针等,直接与硬件内存地址啊,这些东西挂钩,而且系统本身大都用C语言开发,比如WINDOWS,这就在你要开发的应用程序和宿主环境中提供了统一性,你可以更好控制和调用系统DLL,不必作语言之间的BIND,而且C语言不必涉及到OO(因为OO主要是面对人的)而C语言更多地是机器因素,它要求人用机器的思维方式来编程,这句话本身也就说明C语言是靠近机器的,因此它适合用来作系统编程,而RUBY等OO语言用来作面向程序员的高级脚本编程,所谓脚本语言,就是相对系统编程语言来说的,系统编程语言提供了强大的底层编程能力,而RUBY等脚本语言提供了调用这些系统功能的高级应用层的开发..
无论如何,一个程序员是要天天学习新知识的,如果不能快速接受(也即你的基础知识跟不上来),那么基本上你会很累 大学只是学习这个基础知识的阶段,你最好把编译原理,离散数学,汇编程序设计,操作系统,C语言,这些基础弄得滚瓜烂熟,,并积累一些具体的开发经验,,等出了社会之后,你会发现社会上的编程知识跟你在大学学习的东西差了去了,这个时候你的这些基础知识就发挥了很重要的作用,你需要这些基础来理解软件开发中的大学问,新思想,比如设计模式,AOP,OOP,DP,DSL,STL,UML,LAMP,REST,COM,J2EE,
总之钻进去了,也就是一种乐趣..好自为止,
用C++开发要学到什么程度
鉴于这样的话题太有争执性,本文只给出一个参考意见。
都是无穷无尽复杂的细节让初学者停滞了他们学习一门语言的脚步,在你开始满怀喜欢地按书上的例子用C++开始写HELLO WORLD时却被IDE少引用了一个文件之类的问题折腾得一头恼怒浪费不少时间,而书上没有任何一点关于这些的描述,或者网上也只能找到零碎不成文的信息,即使一门语言内部被宣传得天花乱坠比如拥有OO有多少语言机制多么利于复用这种论调泛滥的的今天,在真正动手使用一门语言的时候,作为新手的他们还是会能遇到轻易就把他们击败的细节问题
这些细节问题往往不是大思路大方向(比如什么是OO,这个逻辑用什么来设计好),反而是那些日常时常见到的工具上或语言上的陷阱(象其名家一般研究基础的东西,因为任何东西都是基础的东西通过泛化得来的,而很多人就是基础都搞不明白,,虽然存在大量关于某主题的高级论题,但是基础的东西永远是要求精和熟的),往往这些细节问题可以被理解,但就是难于掌握(这就是那些被称为语言陷阱的东西,然而这是一个大问题,对于软工来说它是),,应该被尽量在语言被设计时就避免而不是人脑避免,比如IDE环境,比如语言细节,比如目标领域的问题,当一门语言复杂到你真正需要掌握这些才能编程的时候,编程就演变为不仅仅是简单的复用了,虽然我们以为OO语言就是简单的复用语言但它们明显做得不够.(没有一门语言,即使RUBY,也没有把语言细节弄得足够简单,使得你可以不管任何语法产生式的机制去直接构建你的应用,,在不损耗逻辑的情况下,而且RUBY的一些语法机制也不是不简单.需要你有深厚的系统知识去理解他们,比如协程,元编程等技术,在接确过一点C++人的眼里,丝毫不比C++简单)
用C++进行开发要学到什么程度,需要什么知识最小集呢,当然要根本目标问题的不同决定不同的复杂度,但语言和工具级的复杂度都是一样的
那么真正要掌握C++进行开发,你需要掌握那些语言级和库级的知识呢
1,至少熟练一个IDE,make,install,,调试,等编译技术,能在编译期出现错误的时候能搞明白基本的I关于DE环境配置的错误
?2,在语言级和库级要明白的就多了出去,比如对STL理念和当中每个LIB的理解,对指针进行理解才能明白诸如函数指针,指针当返回值以返回一个数组等机制,,,当然还有很多很多C++的惯用法,等等,这是主体部分,注意我这里说的是会用,人们可以不懂STL原理和任何实现却照样可以拿来熟练使用的人大有人在.
3,要明白你使用的第三方库的一些知识,要了解它们OO的架构,一个字,要达到一种能用C++使用它们的接口的能力就够了,这就是OO语言宣传它们的资本..又一次,你只会使用就够了,不必懂得库的OO架构,,你需要了解它们透出来供你使用的粗略架构模型和接口就行了.
4,在复用方面,要明白设计的一些知识,知道OO,GP这样基本思想,知道你的应用大家都用OO作了什么设计,你所使用的库用了什么样的封装上的设计.OO并不仅仅是封装,封装是为了复用,,因此OO最终就是为了复用,封装只是中间过程..就像接口并非用来封装一样,而是用来抽象,,一切都是抽象..
5,在开发自己的库和逻辑方面,要明白应用域的一些知识,这样在设计时就能知道要构建什么样的架构.用什么模式来设计等等,用什么语言细节来实现,等等
6,要尽量熟悉以上,多练手,才能快速打出代码,,,,要记住,这个过程很自然,,就像你学好了英语的语法,再多看了一些英语的文章,那么你就可以写出英语文章来了.一切都是习惯用法,和语法游戏,,,除此之外,编程中其它的一切就是设计问题,而不是编码问题了,,,设计的问题是其它领域的问题,比如算法设计,,而不是编码问题(有些书用鸡免同笼这样的问题来放在C语言的书,这对学习C语言本身的语言机制如流程控制有意义,数学问题的复杂性只对研究算法有用,对解释C语言本身无任何作用,而算法是设计通用的,不跟语言相关)
一切在于多看,多写!一开始不要写逻辑和架构过大的逻辑,在懂得设计时就可以接确了.
设计本不存在?当你快速写代码时你根本不会觉得设计的存在,,这是因为编码就是一种习惯,而设计就是一种关于要写出什么样的逻辑的设想,用什么编码方法来体现,,,设计就是对编码进行控制和计划,,这里就是编码跟设计的关系,,难的不是编码,因为所有人都可以学会语法,学会写作习惯,,,但是设计样的文章却千差万别.;.
?设计不仅是算法设计,而且是复用设计
本书目录安排
宜交叉来读本书!!本书的架构是自成体系的,除掉第一部分(书前附录)和最后一部分(书后附录)外,中间三部分是主体,这三部分自成体系,独立且又相互联系,其中的每一节也自成体系,既有知识架构,也有学习方法,技术细节的描述,第二到第三部分很多知识点的讲解都为了第四部分服务,比较侧重于讲解通用的编程知识 (同时兼顾了游戏编程),因为我们本书的主要任务之一是产生一个游戏(本书第四部分《一个例子》),下面一一讲解:
第二部分 导论,这一部分主要是关于编程的导论,
(要懂得一点思想具备一点常识)《设计,编码,,与软工》(编程与思想)这一章解释了三种思想,原语,抽象,组合,,和软件开发的二个重要过程,,软件工程的相关概念,是编程入门的关键
(要懂得一点领域内的数学)《数学与算法》(编程与数学)计算机整个就是架构在数学上的,跟计算机平台实现,算法设计,,架构密切相关,,真正要深入编程,,,对数学的学习是必须的,,千万不要相信别人编程不需学数学!!那是肤浅的编程!!
(要懂得所处的环境)《硬件,平台,网络》(编程与平台)三种大的编程环境,,对他们的理解是必须的,才能走出窗口,,在一个更广阔的思维空间里进行考虑问题和编程。
第三部分 C,C++代码阅读与控制
(要精通所用的语言的语法语义)《语言和语言库》这一节讲解了C++,JAVA和,,JFC言和类库相关的知识,要实际编程,,掌握一门语言和库是必须的
(要精通处理什么样的数据) 《数据结构与数据库》(编程与数据)计算机就是用代码来处理数据,
(要精通写什么样的代码或框架) 《算法与架构》(编程与设计)写什么样的代码,,,不再是写什么样的实现,什么样的算法的问题了,,,而且还是要体现什么设计,,构造什么架构的问题,,如果说面向过程的写代码就是注重设计算法,,,那么在OO这个注重可复用(而且现在这个年代,我们大部分情况下是一个开发者而不再仅仅是一个实现者,我们的确经常是使用外来库来构建应用)的软工时代(时代真的不同了!!),,而且要懂得设计架构,在本节的最后讲到《J2EE大领域学》J2EE是现在最流行的,,OO以后的范型和问题集,因此对它的学习就代表对大多数计算机技术的学习,因为第一部分到这里为止的基础,,所以我们这里可以大致描J2EE的整个模型
(要懂得待处理问题域的细节,为第四部分作准备)《游戏编程与虚拟现实》从这一部分开始讲解多媒体编程和游戏引擎开发的细节,,为下面一部分做好充足准备。。
第1到第3讲的都是范型(1讲的是语言级的,2,3讲的都是非语言级的范型),第4讲的是问题
第四部分 一个综合的例子
这部分就是讲解如何用范型来解决实际问题,最终产生一个可玩的游戏。。注重了架构的学习
《设计----GVWL1.0开发过程》
《编码-----一个NotWar3核心Demo的实现》
.作业与重构
注意各个小主题前面的标号,,有这么几种(组合),,初级和基础主题,,进阶主题,,例子主题,,理论主题,,等等,这些主题都是最新的,一个程序员深入编程或迟或晚都要遇到的(摒弃了一些过时的),,当然进阶就是高级主题,,,基础的主题还是要花大力器的
哲学和基本思想这一节,我会写跟软工密切相关的思想和学习IT知识,以及任何一切知识通用的思想,,比如抽象啊,范式啊这对解释以后OO,都是必须的基础
领域数学并不打算写一切近代数学知识,我只写与计算机领域交集域的那些数学知识,,它对以后一节“机器,平台,网络”是必须的,因为我要在机器平台网络 这一节讲解程序设计语言原理,也就是专业学习必学的编译原理 而数学知识其实还可以被用到以后无论什么时段的编程工作当中,,对机器平台网络这一章的写法中,我并不会突出太多技术细节,我意在只让初学者明白这一切都是怎么回事,学习编译原理为什么会对学习程序设计语言有帮助(是因为它解释了很多语言被设计出来的原理)
机器,平台与网络揭露了软工所处于的三个环境,WEB编程越来越流行了,这就是网络上面的一层抽象(internet是internet,web是web),编译原理其实有很多方面跟汇编有关,这就是跟机器编程有关,,平台 就是OS,,OS就是一个编程层,就像脚本机一样,,,,我们native编程是对本地编程,这里的本地就是指OS,,而虚拟机是可以不需要操作系统就 能运行程序代码的层,,这是另外一个软件运行环境 总结起来,,,这机器,平台与网络讲解了很多“软件运行环境”,特别是我在编译原理讲解中涉及到的机器部分,是最底层的软件运行环境,对设计虚拟机也是必须要用到的知识,,对解释OS的实现又是必须用到的知识,这三个环境是天然不可分割的,,站在软件的角度来看
应用,设计与软工,如果说机器,平台,网络是讲解软件环境,那么这一章这就是讲解软件与人的关系了,一言以概之,这就是软工,软工是为了让软件产品适合“应用”而出现的人类的活动的统称,(界面与逻辑分开啊,数据分开啊什么的),在这个大活动中,涉及到多人合作,,需要考虑软件作为产品的可扩展性的时候,,就需要提出设计和架构这二个字眼和关于它们的一切系统非系统的知识,,而这是很多书本都忽略写出来的 作为产品的,,注意这几个字,,本来软件是不需要写构架的,,但是如果想让软件成为一个好产品,就需要构架,,这就是说“构架不是功能的要求,但却是工程的要求”
以上我说的都是“要懂得的部分”,,,一个程序员只有懂得这些,才算是理解了软工的常识,,,否则一味钻细节,什么都不知道,处于一种很可怜的未开化状态,,更要命的是,不知道何为设计,也就不可能主动领会别人代码或库中的设计之巧,,仅满足于了解算法实现的人是不行的,这样的人,由于一开始不考虑软件作为产品的特性,,最后写出来的东西生命力就不怎么样, 事物之间的联系很重要,你在学习的时候,意识到了计算机和其它东西的联络,然后你构建了这种关系之间的系统,就自成一个学习体系了,这是有价值的地方而且你非了解不可!!因为除非这样,你才能有效地学习,,否则迷茫于庞大的细节,,巨细不分,也就不能界定概念之间是什么关系,,,这是十分造孽,,比
如平台网络机器这一章,“为什么要出现编程语言”,,“我们看到的编程语言到底是什么东西”“它们下面是基于什么离散数学构建的抽象”我把一切功能的达 成的中间层,,无论是软件,还是硬件,都看成抽象,我们今天能看到编程语言为什么要求我们用语法,,而不是直接在语法树上写程序为什么Lisp语言就能 直接在抽象语法树上写程序,而不需要一个语法,,,为什么Yacc是一个没有语法的词法编辑器解释了为什么“我们要用流程控制,逻辑转移”这样的方式写程序,而很多人并不知道,他们学习编译原理,就是为了学到这个知识,这是死读书的人多么大的损失啊,,而我打算择其要点,,组成一条线,,解释语言的由来,,浅而不缺地解释很多很地道的东西,有机地讲解,,择其重点和必要的,去除过时,历史复杂性
我们要编程(如果说第一部分是要懂得的原理,那么这里就谈实践细节,当然要求精通),当然首先用一门语言,我打算举C++和JAVA作为例子,因此语言 和语言库这一部分重点是说到了这二大编程语言,我现在的想法是再增加一个Ruby,,,因为Ruby是新兴的动态脚本语言,是历史所趋,应用所朝,必须要讲解出来否则就是不合理,不完整 当然我也不会讲个大而全,我会从某个线上某个维度上作一个系统讲解 要明白,学语言只是学语法,我们编程是用语言所带的库的,C++有STL,BOOST,JAVA有JDK《J2EE,,所以库是不能不学的,,因此学一
门语言=这本语言的语法+实现了这个语言的某个开发库,,而且程序=算法加数结也是不符合现状的,这也是我接下来要谈到的
而且,其实C++和J2EE作为编译语言,是静态系统语言,因此有设计模式的出台,,,而动态语言就不需要设计模式,因为它是运行期语言,类作为数据结构的定义在运行期可以被动态改变,,根本就不需要编译期cast 这和《C++新思维中》“编译期策略”是一个道理,C++只能提供“编译期动态”以实作出设计模式,而动态语言由于它的性质根本不需要设计模式 有人说设计模式是C++程序的“补丁”,,这话说错也可以,说没错也可以,,这是因为狭隘设计模式之说就是为C++,JAVA这样的静态语言作补丁,, 而广泛的设计,包括设计模式所提出的那些东西,,你知道范式是什么东西就明白我为什么这么说了,广泛的设计是一种意识内你要明白它是广义设计,,但是实际设计时,你要因地制宜的这因地制宜,经济学就指明,,你有自己的资源,,要设计出一个适合你自己的框架,在你的能力和时间范围之内,不要做大而全的超级设计,,虽然大而全正是设计的本质意义所在,,,总而言之,设计的意义是泛义的,但是人的掌握范围之内就得因地制宜,就是多范型设计
根据我们在前面“平台网络OS”那一章提到的,语言的本质就是数据加处理数据的方法写程序的过程就是操作这二个东西,,手工作坊的写软件时代,,就是编程=数据加算法,现在软工时代,编程=数据加算法加架构,其实算法是比架构更广的概念,它侧重于指"功能",而架构侧重指"扩展功能",但这二者都是编码能实现的"真正功能",,说明白点机器语言也是数据加语句,,,这也是一切高级语言在机器端的实现形式
一种语言要最终被体现成数据加语句的形式,那么创造这种形式的语言本身也要提供这二重机制,,这二重机制就是数据加操作数据的方式,数据由原来的数学,字母,这些计算机硬件能直接处理的东西,变成了OO的对象,而处理数据的方法,则变成了架构加算法
比如类形式,,用一种类的形式综合体现了数据和操作数据的方法,,这就是OO
对你死亡级的提醒,请不断写代码唯手熟而的方式是阅读代码,成千上W,并实践!!!第二部分 基础:导论
第1章 系统
1.1 何谓PC
计算机俗称电脑。我们平常谈到的计算机就是指PC。
当然,计算机不光指PC,还可以指服务器,大型机,我们无意去为分别这里面的区别花费时间,这纯粹是一种历史叫法。在不加特别说明的情况下,本书作为编程教学书以下部分我谈到计算机就是指PC。我们是对PC编程。
PC的概念更多地是一个 历史概念而非范畴概念,历史上第一代(注意并非第一台)PC是指1981年8月ibm推出的第一代个人计算机,称为IBM PC,它配备了intel的8088 CPU和Microsoft的MS-DOS,从这里开始,intel确立了它PC行业的CPU霸主地位,微软也慢慢成为了软件领域的巨无霸。Wintel组合出现。
当然,IBM是卖电脑的,Intel是做CPU的,而微软是搞软件的,这三者业务领域不一样。但电脑就是从这个时候开始进入大众生活的,在这之前是一些巨型机,科研设备机器,以及个人爱好者研制的雏形所谓“计算机”。正是这样的发展,带来了计算机向PC发展的态势(硬件上的,软件上的,总体架构上的)。
关于这其中的种种历史,存在有一些趣闻,比如:
l 【硬件上的】:
第一台PC其实是由一个叫毛利的人发明的而不是教科书中普遍谈到的那个巨大的家伙。
l 【软件上的】:
苹果图形界面拉开了计算机图形时代的到来。
50,60年代某段时间一种叫CP/M的操作系统差点取代MSDOS而使它所属的公司成为IBM的合作伙伴。
MSDOS实际上只是一层壳。它是改PCDOS来的。
l 【架构上的】:
CPU是有架构的,AMD和Intel主频之争从来都没停过。
1.2 图灵机与冯氏架构
计算机的产生源于对自动控制(自动机理论)和人工智能(机器人)的研究。
图灵开始研究人工智能的时候那时计算机尚未产生,他的图灵机是对计算机领域的贡献但其实更多的是对人工智能的探测。
图灵机是一种通用自动机器的模型,这种机器有极其简单的形式(因为要能易于实现),然而只要产生足够丰富的变形它可表达并产生一切逻辑(计算函数,表达其它离散算法逻辑等),图灵机在理论上是理想的,它有一个二端无限沿伸的纸带作为存储装置,输入,输出和状态转移函数是一个机器的三要素,这三要素组合并变形可成为一切机器的原型,可解决一切图灵机能解决的问题。因为它揭示了计算机在抽象层次运行的本质即形式计算。所以图灵因为他的这个贡献被称为计算机之父。各种形式的自动机理论随后在那个时代发展开来。
图灵机是被严格证明的。虽然它是一种抽象机难于直接说明,但正是因为这种抽象可用一套形式化的东西来表示并证明(图灵机的运作原理被称为形式计算,是离散数学自动机的一部分)..通过测试的机器就叫图灵完备,,所有通过图灵完备的机器,这说明它们可以产生等价的算法。。可以解决同样的问题。
图灵机的意义是伟大的,因为它是抽象的,所以它能被实现在很多不同层次的地方,比如大到语言识别器,虚拟机模型,小到自动售货机等等。。
如果说图灵机阐述的是一种泛义上的自动机,那么冯氏模型就是专门针对计算机的自动机理论了,以前的机器(在可编程电脑出现之前),指令是硬化的,要为某机器编程相当于重置整个机器。
冯氏机的精神在于"指令存储,顺序执行",在冯氏模型下,执行指令的机制和存储指令的机制是分开的,要换一套程序不需要更换指令系统,因为程序是被内存存储的,取指令器是从RAM中随机取出(某条活动指令总是会在某个内存位置待命,随机的意思就是直接指定内存地址并从里面取码进行执行),并不用预先在内存位置固化程序,然后通过控制和地址总线交互存取到内存,这样CPU只负责执行,对于不同的程序,它可以只用一套指令系统。这样的架构就形成了一种执行指令加调用数据(指令数据在内存中的位置,或编码了的数值和字符)的方式,然而同图灵机一样,这种简单的抽象形式同样可形成高级的具体逻辑。
这样一来,我们编程也成了书写指令和指定供指令操作用的地址,指令内含内存地址为操作码,而如何在内存中组织数据又发展出了数据结构,用底层的观点加数据结构的观点来解释现实事物的解法就形成了算法。(当然,计算机的观点是如何寻址和执行指令,实际上在没有高级编程语言理论之前,远远还没有算法的概念,因此不能说指令是语句,也不能说地址是个变量,地址里面的东西更不能称为数据类型,CPU能直接执行和认识的只是由0,1表达的指令和编码的地址以及各种基本数值和字符,只是后来以人的眼光来看可以无穷地把0,1编码成其它各种逻辑而已,不过在汇编语言级别,这些都不是机器能直接理解的)冯氏机以及它提出的“指令控制存储并串行顺序执行”的理念,这些都深克影响了我们这个时代的编程工作。
l 我们注意到冯氏机主要处理数据和代码,而指令是控制数据的,这使得我们后来的编程工作的抽象焦点在于数据和语句。这是冯氏模型对编程工作最大的影响。
l 我们注意到指令是被串行执行的,这说明冯氏模型一开始就被设计成为非并行计算机,因此在后来编程中,要实现并发逻辑需要从软件上和设计上去突破。
l 其它。。
1.3计算机能干什么
我们要首先懂得计算机能干什么,它的功能发源主要在哪里?这样才能懂得编程的出发点和目的。这就不得不首先谈谈计算机系统的组成。
首先,CPU是PC中的总控制中心,在前一节中我们谈到CPU执行的过程就是一个不断取指令并译码的顺序过程(所以本质上它其实并不智能,PC只是一台高速自动机而已),其实CPU不但处理它自己的事情而且是作为整个PC的总控制中心存在的,CPU不但接管了内存管理,还接管了其它硬件,比如它把显存归入它的管理统一跟主内存编码,而且把硬件消息归为它的中断并把其中断处理程序统一跟内存编码。CPU在执行中(有一个时钟发生器指导CPU不断地运行)不断变换其状态,输入输出则是这些二进制(因此整个PC做的工作都是某种意义上的IO)。总而言之,冯氏架构中,CPU统冶了整个机器,内存二把手,其它硬件则是被它统治的。在CPU眼里,一切都是内存地址和指令(这就对编码工作提供了无比便利的条件,使得冯氏下的编码工作变得无比统一)。
CPU中最主要的二个部件是控制器和运算器,计算机之所以被称为计算机,是因为它提供了形式计算,还是CPU里面的逻辑和算术运算呢,当然是前者。实际上运算器和逻辑器的地位就像协处理器一样,是CPU不必要的组件,是CPU扩展它的功能加的电路板。这些硬件功能固然是计算机功能的重要组成部分并影响对其的编程工作,然而并非全部。
计算机逻辑主要发源于二个地方,这决定了他的功能和对于编程的意义所在。
l 首先,计算机各个部件都是有功能的,比如浮点器可以表达浮点数并处理,计算机籍此可以直接表达硬件级的浮点抽象以及用浮点表达更大的编码了的抽象(实际上也存在软件的浮点处理器),这就为编程引入了浮点逻辑。另外一个道理,你不能编程指使PC为你做“给我泡一杯牛奶”之类的事情,因为它不是硬件上能提供的功能和逻辑所在(即使是抽象也得不到),只有当PC真正接入了一台牛奶机之后,你才能编程实现诸如泡牛奶的硬件功能。
l 计算机的功能不但在于表达硬件逻辑,而且更大的地方在于表达广泛意义上的应用逻辑。我们可以对PC编程创造一个游戏,虽然图形功能是来源于显卡的,但是游戏世界的逻辑明显不是硬件的。Web应用就是这个道理。
在机器级别编程,我们无法表达高级的应用逻辑,因为0,1能直接编码的逻辑是非常有限的,只有当PC发展到提供了操作系统,进程等高级逻辑之后,我们才能在一个新的工作起点上构造更强大的应用逻辑。
所幸的是,当编程发展到高级语言阶段之后,这些机器的细节都被完全抽象化了。
1.4 内存地址
既然冯氏架构就是将执行指令的CPU和存放程序的内存分开的一种架构机制,CPU中集成了对内存的管理,在CPU的眼里一切都是内存地址,而且这导致了冯氏模型下编程的统一性。那么CPU是如何与内存发生关系的呢? 学习这个有助于我们理解操作系统诸如这样的软件的系统逻辑是如何在硬件基础上包装出来的。
CPU与内存如何发生联系被称为CPU的存储管理机制,CPU管理内存的硬件是它的地址总线和数据总线(我们知道CPU虽然自己处理数据,但他同时还主要做着一种IO的动作,CPU管理IO的硬件被集成在主板上一块被称为芯片组的地方),其中地址总线是负责寻址机制的通道,而数据总线表示CPU能一次性处理的数据通道,地址线数与数据线性往往长度不一,这就导致了CPU的寻址跟处理产生了一对矛盾,地址线决定了它能看到(CPU能使用到的)和管理到的内存总量(物理地址),而数据线决定了它能一次性处理的数据长度和能表示的地址形式(逻辑地址),,,这就是表示(逻辑地址形式)和实际内存(物理地址)上的矛盾。
撇开其它因素,我们就事论事来讨论这个矛盾,20位地址线可以使用2^20个最小内存单元即1MB的内存空间(这就是说使得这种CPU的一个任务理论上可使用至多1MB的线性空间,因为它只能寻址到这么大的地儿)但16位CPU中的寄存器只能表示前16位(CPU是用寄存器来表示地址的,这就是说虽然CPU能看到整整1MB的空间,但他一口吃不下其中的最小一个单元,因为它首先都不能直接表达这个单元)。因此CPU要表达和要用尽这1MB的空间,不能以直接线性对应的方式来表达。除非数据线多于或等于地址线。
间接的方法就是设置另一层抽象。可令16位先表达一个大小为64KB的段,1MB的内存刚好等于1MB / 64KB倍数个这样大小的段。在这种情况下,内存就不再是绝对线性的了(当然,实际上所有内存都是线性的,这里说的是分段之后的逻辑情况下,而且你不用担心CPU认不认识这样的划段法因为它的确认识,下面会谈到一个实模式的东西),而是被划分成了一个一个的段(在段内才是线性的),16位用来表示段内的每个最小内存单元,空出的4位不再用来表达内存本身,可以用来表达段本身。
以上讨论的情况是8086CPU在实模式运行的存储管理逻辑,即从逻辑地址(CPU要形成任务用到的地址形式)到真实物理地址的编码(实际机器有的地址),这中间要经过一个变换,CPU负责这个转换。无论在多少长度的地址线和多少长度的数据线产生矛盾的情况下,都会由CPU负责这个转换,不过32位数据线的CPU转换方式要特别复杂而已(特殊的分段方式再加一个分页的方式,段寄存器不像实模式那样用来实际存储物理地址的线性表示,它只用来实现硬件级计算最终物理地址的一个中间存储)。
在32位CPU出现之后,寄存器能表示的逻辑地址早就是4G了,而地址总线超过了32位(除非地址总线少于逻辑能表示的数量才需要实模式那样的分段,然而32位CPU下并没有产生这样的矛盾因此可以以线性地址的直接表示方式来表示逻辑任务线性空间,然而32位CPU照样也实现了一种转换机制,这是因为它需要实现更强大的保护模式而不仅仅是完成寻址。
综上所述,逻辑表示是寄存器能表示的地址形式,,真实地址是系统装配的内存量,而线性表示是CPU用来形成任务的任务地址。统称为任务空间。不跟硬件地址相关,也不跟逻辑表示形式相关,这完全是一种独立机制的编码,32位CPU下,一个任务的线性空间表示总是4G(注意总是这个词),只是一个转换机制会负责这逻辑地址到线性地址的转换,,然后又有一个转换机制负责线性地址到真实物理地址的转换,程序员完全不必为线性地址过少和这中间的转换而烦恼那是CPU必须管的事,,否则32位的汇编工作几乎要手动驱动CPU。
明白了以上这三个概念,让我们再来看下面的章节。
1.5 分段和分页以及保护模式
32位的CPU利用它的转换机制可以保证4G空间一直存在内存中(这就是说,实际上并没有一个实际的4G空间在内存中,只是CPU可以看到一个4G大的线性段,能以它为基础形成任务直接供程序使用这才是CPU关注的)..这样的话,对于编程来说,只要是在保护模式下,我们都可以拥有一个4G的编程可用空间,不必调进调出的(它本来就一直在内存中为CPU所看见)。。
上述32位CPU的转换机制是分段跟分页的综合作用。分段机制不管这个4G空间的实际调进调出,因为它不负责实际分配内存,它只负责逻辑地址到线性地址的转换过程..实际分配内存的工作由分页机制来完成,它负责线性地址最终到实际的物理地址的转换,它把这分段后形成的4G虚拟的空间用来调度真实的内存页,内存页就是真实的物理地址的载体,分页机制只需保证生成的页面大小总和局限在这4G空间中即可。。页面是随用随载,调进调出的,以较小的单位而不是段来实际使用内存,,这就加大了内存的使用率(虽然分页并非百分百做得到如此)。
要深切理解CPU是如何完成分段分页形成任务可用空间的过程是一个精微的学说,段选择符,门,LDT,GDT,pae (CPU中有一个pae位可以保证所有CPU都只在概念上只看到这一大小)这些概念之间是如何相互间发生关系并维护这样一个4G空间。以及这个机制产生的结果和意义所在,需要翻阅相关的书籍。下面试阐述一二:
l CPU首先检查这个选择符的ti字段,以决定是选择到ldt还是gdt中选择描述符,然后检查相应的索引以在ldt或gdt(这些都是内存中的数据结构表,表驱动方式)找到最终的描述符。。这些符结构都在4g内存的高端部分,注意是在内存中..找到描述符之后,再以判断选择一样的方式在描述符中判断各个字段,主要是生成段基和段长,段的三个权cpl,dpl,rpl..
l 比如在如下的一个指令中 mov ds,ax, ax存储的并不是指向ds的指针,,也就是说它并不实际存储ds的地址。而是一个选择符(注意,第一它不是段描述符,第二它段选择符是一个32位的数据结构,它的各个字段表明了不同的意义,组成整个段选择符的意义),,,段寄存器大小有限,CPU中的寄存器只用来存储指针值,或者描述用的数据结构,比如在这里是一个段选择符。。
l CPU就是靠以上方式来实现对于段机制的保护的,每一条指令都有内存读写逻辑,每一个内存读写逻辑都有这样的寻址,最终要涉及到进入段中。涉及到保护模式的一系列机制。。
l 门是CPU中的一种迂回机制,有调用门,任务门,中断门,异常门,这四种门的用途不一样,但都是为了实现CPU对内存访问进行保护的一种迂回机制(比如数据访问权限啊,任务安全切换啊,中断正常返回啊),调用门实现了数据访问的