《学习C++:实践者的方法.docx》由会员分享,可在线阅读,更多相关《学习C++:实践者的方法.docx(31页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、学习C+:实践者的方法By刘未鹏(pongba)C的罗浮宫()注该文处于Beta阶段等待反应中请勿转载前言我的blog以前很长一段时间关注的都是C中的技术细节乃至于读者以及应者都寥寥。然而5月份的时候写的一篇“浏览量却到达了3万多在blog上所有文章中却是最高的且远远超过了第二位评论数目也有一百多。为什么独独这篇可以激起这么多的回应想必是国内的C社群被C压抑太久或严格来讲是被C的教育方式压抑太久。实际上不管是在各大国内论坛上还是在comp.lang.c.moderated这样的国际C论坛上乃至于在douban上的小组内有心者都会发现对C语言的细节的关注一直都没有停顿过同样对C语言的细节的抱怨也
2、从来都没有停顿过。一个例子就是comp.lang.c.moderated上的一个技术牛人JamesKanze讲的他讲接触C十年度了到如今还需要不时去翻C标准。这就难怪EricRaymond老大在?TheArtofUnixProgramming?中讲“C是反紧凑的了。C中的细节过多就算都看过了也不可能都记住。更关键的是就算都记住了也不能让你成为一个真正的好程序员。绝大多数人都把细节过多或用贬义词来讲就是“阴暗角落过多归结为C的本质问题认为一切邪恶由此而生。也正因此大约9月份的时候Linus在邮件列表上讲“C是一门有思想包袱的语言仅仅是为了让程序员远离C我也要用C。这句短短的话在国内引起了很大的反
3、响最初是然后以及都发表了自己的看法我也写了一篇“后来发给BjarneBjarne对这篇文章做了一个。然而这一通浑水搅过之后我相信引起的变化未必很大。大多数原先的反对者能从中找出反对的理由于是更加反对大多数原先的赞同者也能从中找到赞同的理由于是更加赞同而剩下来的原先没有明确意见的看双方各有各的道理可能还是没有头绪。摆脱自己效劳偏见理性考虑的前提?决策与判断?上提到过一个有趣的真实故事1980年度的某一天美国空战司令部的计算机突然发出警报苏联的一枚核弹正在向美国外乡飞来。司令部立即调兵遣将迅速为一场核战做好了准备然而3分钟之后工程人员发现是计算机的一个小零部件故障造成的。然而这场虚惊之后群众的反响
4、才是真正有意思的原先支持核武装的认为如今感觉更加平安了因为“事实证明这类的故障是完全可克制的而原先反对核武装的那么认为更不平安了因为“这类错误信号可能导致苏联过度反响引发真正的核战。类似的情况也发生在三里岛核泄露事件之后同样的反对者认为“这说明管理部门没有方法平安管理核能支持者认为“这正说明这样的危险没有想像得那么严重是可克制的。社会心理学把诸如此类的现象总结为“自己效劳偏见。不幸的是“真理越辩越明其实只适用于理性考虑者。为什么啰嗦这么一大通呢就是因为一直以来泛滥于程序员社群的“语言之争背后真正的原因其实并不在于语言本质上的优劣而在于观察者的眼睛。在观察者的眼睛里面语言并非一门工具而是自己花了
5、N多时间其中尤数C为最来“修炼的技能对于这样的技能被否认无疑等同于自己被否认。所以从心理学上讲语言并不是工具尽管一直有这么一种呼吁而是信仰。这样的信仰在越是花得时间久的语言上越是剧烈。有趣的是几乎所有的“热闹的社群都有这样的现象Java、Python、Ruby莫不如是因为就算语言本身不复杂程序员仍然还是要投入大量的精力去学习各种各样的框架类库想想Java的那些框架。因此这些语言社区的信仰未必不比C社群的强烈。然而一旦弄清我们为什么会把语言当成信仰就非常有助于摆脱在对待语言时的“自己效劳偏见从客观的角度去对待问题。“当你看到的是支持某个意见的证据时试着去想一想有哪些证据是不支持它的。那么为什么要
6、摆脱自己效劳偏见讲小了是为了成为一个更优秀的程序员谁也不祈望因为偏见而去使用一门低效的语言乃至不妥当的语言。讲大了是节省生命因为偏见可能导致越陷越深浪费时间。所以假如你可以理性的考虑我们将要讨论的问题防止自己效劳偏见就当你从来没有花时间在C上一样。那么我们便可以开场讨论真正的问题了。前言2如今几乎每个学习C的都知道C的核心问题是其复杂性甚至本身不在C社群的也知道这是事实。群众的眼睛是雪亮的何况这还是个太显而易见的事实。但看了无数篇阐述C复杂性的文章以及争论C复杂性的吐沫星子包括我前段时间写的两篇关于C的总结。我始终都有一个感觉没分析透就跟盲人摸象一样。正如“WhyC的一位读者批评的我在文章里面
7、没有写明到底哪些是C的“非本质复杂性。当然我自己凭感觉就能知道而接触C一段时间的人大致也能知道但新手乃至非新手那么对我所谓的“非本质复杂性根本没有一个详细的认识这就使得那篇“WhyC脱离了本来的意图面向所有C使用者以及学习者。同样的原因在写了“你应当怎样学习C一文之后当孟岩先生邀请我给?程序员?写一个系列的文章介绍一下我在接触C的经过中的态度以及认识转变时我固然非常快乐的容许了但直到如今3个月过去了还是颗粒无收。为什么因为我觉得真正本质的问题没有被明晰的触摸到所以直到如今我都没有动笔免得废话讲了一大堆除了能被当成小讲读读之外对真正考虑是否要学习乃至使用C的人未必有什么实际用途。然而这么个念头一
8、直都放在潜意识里面。前一阵子以及Bjarne通信谈到了关于C复杂性的一些想法在邮件里面总结了一下C的复杂性来源感觉思路明晰了许多。而这篇文章要到达的目的正是传达对C的复杂性的一个详细而明确的认识有了这个认识作为支持我们便可以推导出学习C的最正确理论者的方法。为什么要学习并使用C显然假如找不出要学习C的理由那么谈什么“正确的学习方法等于是废话。首先重复一句Bjarne的话“我们的系统已经是极度复杂的了为了避开C的复杂性而干脆不用CLinus的做法无异于因噎废食。在所有可用C以及C的领域C都是比C更好的语言。当我讲“更好的时候我讲的是C拥有比C更平安的类型检查、更好的抽象机制、更优秀的库。当然凡事
9、都有例外假如你做的工程1不大。2编码中用不到什么抽象机制甚至ADT抽象数据类型例如std:complex这种不含多态以及继承的也用不到RAII也用不到异常也用不到。3你连根底库如简化资源管理的智能指针、智能容器都用不着。那么也许你用C确实没问题所以假如你的情况如此不用以及我争论因为我无法反驳你。我们这里讲的领域大致是Bjarne在“里面列出来的那些地方。底线是假如把C中的众多不必要的复杂性去掉留下那些本质的重要的语言特性简化语言模型消除历史包袱。即便是C的反对者也许也很难找到理由讲“我还是不用C。在我看来一个真正从理论意义上理性反对使用C的人只有一个理由C的复杂性带来的混乱抵消乃至超过了C的抽
10、象机制以及库在他的特定工程中带来的好处。值得注意的是这里需要防止一个陷阱就是一旦人们认定了“C不好那么这个理由就会“长出自己的脚来即就算我们拿掉C的复杂性他们可能也会坚持还是不用C并为之找一堆理由。我假定你不是这样的人。不过也许最可能的是他会讲“问题是我们今天用的C并非如此简洁你的假设不成立。是的我的假设不成立。但固然我们无法消除复杂性我们实际上是可以容易地避开复杂性避短扬长的。这也是本文的要点容我后面再详述。当然到如今你可能还是会讲。我还是不用C因为我可以用D或假如你本来做的工程就不需要C你那么可能会讲我用Python。首先假如你的工程能用Java/Python乃至Ruby做那么用C是自讨苦
11、吃。因为能用那些语言代表你的工程在效率上本身要求就不高那么用一门效率上讨不到太大好处复杂性上却绰绰有余的语言有什么价值呢其次假如你的工程效率是很重要的你可能会讲可以用D。然而现实是D在工业界尤其是国内被运用得非常少几乎没有。而C却有大量的既有代码已经使用C去做他们的产品的公司在很长一段时间之内几乎是不可能用别的语言重写代码的正如Joel所讲决定重写一个非平凡的代码基自杀。所以我们至少要注意以下两个明显的事实事实1C在工业界仍有稳定的核心市场。这个事实大概不需要多加阐述很多大公司的核心技术还是要靠C来支撑的见Bjarne主页上的C应用列表。所谓事实就是未必是大众最愿意成认的情况但又不得不成认。C
12、积累了庞大的代码基这个代码基不是一朝一夕可以推翻的。D从语言角度来讲确实优于C但最关键的就是还没有深化工业界也许根本原因是没有钱支持但这不是我们讨论的重点。而C呢根据Bjarne本人的讲法他的观察是主流工业界的趋势一直是“从C到C的而不是反过来至少在欧美是如此。在国内我们那么可以通过CSDN上的招聘情况得到一个大致类似的信息。事实2C程序员往往能享受到有竞争力的薪酬。是的这不是一篇不食人间烟火的技术文章。这个事实基于的逻辑很简单物以稀为贵。AndreiAlexandrescu这次来中国SD2.0大会的时候在承受采访时也讲过“最赚钱的软件如MSOffice是C写的。孟岩也在blog上提到这么个事
13、实我想他作为CSDN的技术总编业界观察肯定比我明晰深入。所以我这里就不多废话了。当然以上逻辑并不就意味着在怂恿你去学C一切还要看你的兴趣。所以假如你志不在C身处的那些应用领域那这篇文章并非为你而写。 “C的复杂性是根本原因一个有破绽的推理一旦我们认识了C在一些领域是有需求的值得学习以及掌握的这个问题之后就可以接下来讨论“如何正确学习以及掌握C这个核心问题了。其实对于这个问题Bjarne已经宣传了十年度。早在99年度的时候Bjarne就写了“并在好几篇技术访谈还有里面提到怎样正确对待以及使用C中支持的多种抽象机制的问题。AndrewKoenig也写了一本当代C教程?AcceleratedC?这本
14、书后面还会提到。然而这么多年度来C社群的状况改善了吗就我所知就算有改善也是很小的。学习者还是盲目钻语言细节只见树木不见森林网上还是弥漫着各种各样的“技术文章以及不靠谱的“学习C的XX个建议一些业界的有身份的专家还是在一本接一本的出语言孔乙己的书写一些普通程序员八辈子用不着的技巧以及碰不着的角落而业界真正使用C的公司在面试的时候还总是问一些边边角角的细节问题而不是考察编程的根本素养不掌握所有的语言细节也不能让你成为一个合格的程序员。这个面试理念是错误的估计其背后的推理应该是“假如这个家伙不知道这个细节那么估计他对语言也熟悉不到哪儿去而假如他知道那么固然他可能并不是好的程序员但我们还是可以就后一个
15、问题进一步测试的这个理念的问题在于对语言熟悉到一定程度什么程度后面会详细建议就已经可以很好的编程了剩下的只需查查文档而很多公司在测试“对语言熟悉程度的时候走得明显太远了比方问临时对象生命期以及析构顺序当然是无可厚非的但问怎样防止一个类被拷贝或怎样防止其构建在堆上当然有些语言知识是必需要提早掌握的详细有哪些后面会提到面试的时候并非不能问语言细节关键是“问哪些。所以讲事实3C的整个生态圈这么些年度来在学习C的哲学上实在没有多少改善。为什么是因为Bjarne介绍的学习方法在技术上没有讲到点子上是AndrewKoenig的书写得不够好讲了谁也不会相信。因为实际上这里的原因根本不是技术上的而是非技术的。
16、众所周知的一个事实是从最表层讲C的最严重问题是在语言学习阶段占用了学习者的过多时间。翻一翻你的C书架或电子书目录绝大多数的C“经典都是在讲语言。在我们通常的意义上要“入门C在语言上需要耗的时间一般要两三年度。而要“精通C那么搞不好需要耗上十年度八年度的。这跟PeterNorvig讲的“十年度学习编程其实不是一回事人家那是讲一般意义上的编程技能不是叫你当语言律师。那为什么我讲“C的复杂性是根本原因是个有破绽的推理呢因为要让人们在使用一门语言去做事情之前耗上大量时间去学习语言中各种复杂性除了语言本身的复杂性的事实之外还有一个重要的事实那就是学习者的态度以及更重要的方法。而目前大多数C学习者的态度以
17、及方法是什么呢在真正用C之前看上一摞语言书日常编程八辈子都未必用得到。而为什么会存在这样的学习态度呢这就是真正需要解释的问题。实际上有两方面的原因事实4市面上的绝大多数C书籍包括很多被人们广泛称为“必读经典的实际上都是反面教材。也就是讲随意你拿起哪本C书籍包括很多被人们广泛称为“必读经典的那么有很大的可能这本书中的内容不是你应该学的而是你不应该学的。我之所以这么讲有两个原因因为一我曾经是受害者。二也是更本质性的原因这些所谓的必读经典充满的是介绍C中的陷阱以及对于C的缺陷的各种workarounds好听一点叫Idioms惯用法或者techniques技术又因为C中的这类陷阱以及缺陷实在数不胜数所
18、以就拉出了一个“长尾这类书籍在所有语言中都存在“C缺陷以及陷阱、“EffectiveJava、“EffectiveC#等等然而在C里面这个尾巴十分长导致这类书数不胜数。三这些书中列出来的缺陷以及陷阱根本不区分常见程度对于一个用本程序员来讲应该祈望看到“从最常见的问题到最不常见的问题这样的顺序来罗列内容然而这些书里面要么全部混在一起要么按照“资源管理、类设计、泛型这样的技术分类来介绍内容这根本毫无帮助假如我看到一个章节的内容我当然知道它讲的是类设计还是资源管理还用废话么使得一个学习者无法区分并将最重要的时间花在最常见的问题之上。最最关键的是这些书当中介绍的内容与成为一个好程序员根本毫无关系它们顶
19、多只能告诉你嗨小心跌入这个陷阱。或告诉你嗨你知道当你八辈子都不一定遇到遇到这个需求的时候可以通过这个技巧来得以解决吗结果读了一本又一本之后你脑袋里除了塞满了“制止、“戒备、“灯泡符号之外真正的编程素质却是一无长进。又或有这样一类书热衷于解释语言实现背后的机制然而语言特性本质上是干嘛用的是用来在实际编码中进展抽象的讲得好听一点就是“设计不是用来告诉你这个特性是怎么支持的。比方我就见过以下的情景面试官问“你知道虚函数吗得到的答复是一堆关于虚函数表机制的解释。面试官又问“那虚函数的好处是什么呢到底为什么要虚函数呢得到的答复是“恩啊就是多态吧这时已经觉得答复不够深入了。再问“那多态是干嘛的呢哑口无言。
20、事实5就算记住一门语言的所有细节也不能让你成为一个合格的程序员。事实6解析语言实现虽然有其理论意义在极端场合的hack手法和出现底层bug的时候迅速定位问题然而假如为了解析语言机制而去解析语言机制便脱离了学习语言的本意了。在C里面这样的情况很多见知道了语言实现的底层机制却不知道语言特性本身的意义在什么地方。本末倒置。为什么书害的。二这类书当中介绍的所有情景加起来其实只属于那20%二八法那么甚至20%都不到的场景终究是哪些书后面会介绍我不便直接列出书名打击面太大但我会把我认为essential的书列出来。这就是为什么我讲“八辈子都用不着的原因。事实780%的C书籍包括一些“经典只涉及到20%或更
21、少的场景。你可能会讲那难道这些书就根本不值得看了吗我的答复是对。根本不值得看。但是值得放在旁边作为必要的时候的参考记住从索引或者目录翻起只看严格必要的局部假如你是个严肃的程序员的话。因为不管成认与否墨菲法那么的强大力量是不可无视的假如有一个可能遇到的陷阱那么总会遇到的。而同样C的那些奇技淫巧也并非空穴来风总有时候会需要用到的。但是你不需要预先把C的所有细节以及技巧存在脑子里才可以去编程即建议1有区分力地浏览包括那些被广泛称为“经典的C书籍。假如书中介绍的某块内容你认为在日常编程中根本不会用到属于20%场景那么也许最好的做法是非常大概的阅读一下留个印象而不是顺着这条线深究下去。关于在初学的时候应
22、该读哪些书后面还会提到。实际上除了语言无关的编程修养之外需要浏览什么书后面会提到对于C这门特定的语言要开场用它来编程你只需知道一些根底但重要的语言知识需要浏览哪些书后面会提到和“C里面有许多缺陷以及陷阱的事实并且建议2养成随时查阅资料以及文档的习惯。 “查文档几乎可以讲是作为一个程序员最重要的才能是的才能了它是如此重要以致于在英文里面有一个专门的缩写。为什么这个才能如此重要原因很简单编程领域的知识太鸡零狗碎了。不仅知识量宏大而且知识的细节性简直是任何学科都无与伦比的随意找一个框架类库看看它的API文档吧。所以把如此巨量的信息预先放在脑子里不仅不实际而且简直是自作孽。你需要的是“元才能也就是查文
23、档的才能从你手头遇到的问题开场进展正确合理的分析预测问题的解决方案可能在什么地方找到关于后者的资料浏览理解运用。同样在C中也是如此假如你从学习C一开场就抱着这种态度的话那么即便等到面试的时候被问到某个语言细节你可以以胸有成竹的讲你固然并不知道这个细节但在实际编码中遇到相应问题的时候肯定会找到适宜的参考资料并很快解决问题解决问题才是最终目的。当然更大的可能性是你在平常编码中已经接触过了最常见的那80%的陷阱以及技巧了由于你用的是理论指导性的学习方式所以你遇到的需要去学习的陷阱以及技巧几乎肯定都是常见场景下的比没头苍蝇似的逮住一本C“经典就“细细研读的方法要高效N倍因为在没有理论经历的情况下你很可
24、能会认为其中的每个技巧每个陷阱都是同样概率发作的。为什么市面上的C书热衷于那些细节以及技巧呢你用一个天生用来开啤酒瓶的工具开了啤酒瓶不但啥成就感也没有而且谁也不会觉得你牛13。然而假如你创造了一种用两根筷子也能翻开啤酒瓶的方法或你干脆生就一口好牙可以把瓶盖啃开那也许就大不一样了。人家就会觉得你很好很强大。事实8每个人都喜欢戴着脚镣跳舞。也就是讲假如你用一个天生为某个目的的工具来做他该做的事情没有人会喝彩你也不会觉得了不起。但假如你用两个本身不是为某个目的的工具组合出新功能的话你就是“创新者尽管也许本来就有某个现成的工具可用。而C那么是这些“创新的土壤是的我讲的就是无穷无尽的workaround
25、s以及惯用法。但问题是这些“创新其实根本不是创新你必须认识到的是他们都只不过是在没有first-class解决方案的前提下不得已折腾出来的替补方案。是的它们某种程度上确实可以叫创新甚至研究可行的解决方案本身也是一件非常有意思的事情但事实9我知道它们很有趣但实际上它们只是补丁方案。是的不要因为这些“创新方案有趣就忍不住一头钻进去。你之所以觉得有趣是因为当你一定程度上熟悉了C之后C的所有一切包括缺陷对你来讲就成了一个“既定事实一个背景一个习以为常的东西人是有很强的适应性的。因此当你发如今这个习以为常的环境下居然出现了新的可能性时你当然是会欢呼雀跃的比方我当年度读?ModernCDesign?的时候
26、就有一次从早读到晚午饭都没吃然而实际上呢其它语言中也许早就有first-class的支持了其它语言也许根本不需要这个惯用法因为它们就没有这些缺陷。此外从理论的角度来讲更重要的是这些“解决方案也许你平时编程根本就用不到。不我当然不是讲这些补丁方案不重要。正如前面所讲C中繁杂的技巧并非空穴来风总有实际问题在背后驱动的。但问题是对于我们日常编程来讲这些“实际问题简直是八杆子打不着的。犯不着先费上80%的劲儿把20%时候才用到的东西揣在脑子里用的时候查文档或者书就行了。看到这里塑造C中特定的心态哲学的另一个原因想必你也已经知道了。实际上这个原因才是真正根本的。前面讲的一个原因是C书籍市场教育造就的然而
27、为什么人们喜欢写这些书呢进一步讲为什么人们喜欢读这些书呢我成认我也曾经读得津津有味。答案很简单心理。每个人都喜欢戴着脚镣跳舞事实8。认识到这一点不是为了提倡它而是只有当我们认识到自己为什么会津津有味地去钻研一堆补丁解决方案的时候我们才真正可以摆脱它们的吸引。总而言之C的复杂性只是一个必要条件并非问题的根本症结。根本症结在于人的心理每个人都喜欢戴着脚镣跳舞并且以为是“创新。意识到这一点之后可以帮我们防止被各种各样名目繁多的语言细节以及技巧占去不必要的时间。然而C的复杂性始终是一个不可回避的现实。C中有大量的陷阱以及缺陷后者导致了数目惊人的惯用法以及workarounds。不加选择的全盘预先学习是
28、非常糟糕的做法不仅低效而且根本没有必要实在是浪费生命。爱因斯坦曾经讲过“我只想知道他宇宙的设计理念其它的都是细节。然而正如另一些读者指出的假如对C中的这些细节事先一点都没有概念的话那么实际编码中一旦遇到恐怕就变成没头苍蝇了也许到哪里去RTFM都不知道。这也是为什么那么多C面试都会不厌其烦地问一些有代表性的语言细节的原因。把细节全盘装在脑子里虽然不好但对细节一无所知同样也不是个方法。那么对于C程序员来讲在学习中终究应该以如何的态度以及学习方法来对付C的复杂性呢其实答案也非常简单首先有一些很重要必须的语言细节特性是需要掌握的然后我们只需知道在C中大抵有哪些地方有复杂性陷阱、缺陷那么遇到问题的时候自
29、然可以知道到哪儿去寻找答案了。详细的建议在后文。C的复杂性分类本来这一节是打算做成一个C复杂性索引的然而一来C的复杂性过多二来网上其实已经有许多资料比方BjarneStroustrup本人的就是一个很好的文档加上市面上的大多数C书里面也不停的讲语言细节因此实际上我们不是缺乏资料而是缺乏一种索引这些资料的方法和一种掌控这些复杂性的。由于以上原因这里并不详细罗列C的复杂性而是提供一个分类标准。C的复杂性有两种分类方法一是分为非本质复杂性以及本质复杂性其中非本质复杂性分为缺陷以及陷阱两类。另一种分类方法是按照场景分类库开发场景下的复杂性以及日常编码的复杂性。从从事日常编码的理论者的角度来讲采用后一种
30、分类可以让我们迅速掌握80%场景下的复杂性。二八法那么以下通过列举一些常见的例子来解释这种分类标准80%场景下的复杂性1.资源管理C日常复杂性的最主要来源深拷贝浅拷贝类的四个特殊成员函数使用STLRAII惯用法智能指针等等。2.对象生命期部分全局对象生存期临时对象销毁对象构造析构顺序等等。3.多态4.重载决议5.异常除非你不用异常栈开解stack-unwinding的经过什么时候抛出异常在什么抽象层面上抛出异常等等。6.undefinedunspecifiedimplementationdefined三种行为的区别ii是undefinedbehavior未定义行为即“有问题的坏的行为理论上什么
31、事情都可能发生参数的求值顺序是unspecified未指定的即“你不能依赖某个特定顺序但其行为是良好定义的当一个double转换至一个float时假如double变量的值不能准确表达在一个float中那么选取下一个接近的离散值还是上一个接近的离散值是implementationdefined实现定义的即“你可以在实现商的编译器文档中找到讲明。这些问题会影响到你编写可移植的代码。注以上只是一个不完全列表用于演示该分类标准的意义实际上假如我们只考虑“80%场景下的复杂性记忆以及学习的负担便会大大减小。20%场景下的复杂性1.对象内存布局2.模板偏特化非类型模板参数模板参数推导规那么实例化二段式名字
32、查找元编程等等。3.名字查找绑定规那么4.各种缺陷和缺陷衍生的workaroundsC书中把这些叫做“技术不支持conceptsboost.concept_check库类型透明的typedeftrue-typedef惯用法弱类型的枚举强枚举惯用法隐式bool转换safe-bool惯用法自定义类型不支持初始化列表boost.assign库孱弱的元编程支持type-traits惯用法tag-dispatch惯用法boost.enable_if库boost.static_assert库右值缺陷loki.mojo库不支持可变数目的模板参数列表type-list惯用法不支持native的alignmen
33、t指定。注以上只是一个不完全列表。你会发现这些细节或者技术在日常编程中极少用到尤其是各种语言缺陷衍生出来的workarounds构成了一个宏大的长尾在无论是C的书还是文献中都占有了很大的比重们称它们为技术然而实际上这些“技术绝大多数只在库开发当中需要用到。非本质复杂性本质复杂性此外考虑另一种分类方法也是有帮助的即分为非本质复杂性以及本质复杂性。非本质复杂性不完全列表1.缺陷指可以克制的问题但解决方案很笨拙C的书里面把克制缺陷的workarounds称作技术我觉得非常误导例子在前面已经列了一堆了。2.陷阱指无法克制的问题只能小心绕过假如跌进去那就意味着你不知道这个陷阱那么很大可能性你也不知道从哪
34、去解决这个问题一般来讲作为一个合格的程序员不管是不是C程序员80%场景下的语言陷阱是需要记住才行的。比方深拷贝浅拷贝基类的析构函数应当为虚缺省生成的类成员函数求值顺序序列点类成员初始化顺序声明顺序导致不可移植代码的实现相关问题等。本质复杂性不完全列表1.内存管理2.对象生命期3.重载决议4.名字查找5.模板参数推导规那么6.异常7.OO动态以及GP静态两种范式的应用场景以及交互总而言之这一节的目的是要告诉你从一个较高的层次去把握C中的复杂性。其中最重要的一个指导思想就是在学习的经过中注意你正学习的技术或者细节到底是80%场景下的还是20%场景下的一般来讲读完两本书后面会提到之后你就可以很容易的
35、对此进展判断了假如是20%场景下的有大量这类复杂性其中尤数各种各样的workarounds为巨那么也许最好的做法是只记住一个大概不去作任何深究。此外一般来讲不管使用哪门语言认识语言陷阱对于编程来讲都是一个必要的条件语言陷阱的特点是假如你掉进去了那么很大可能意味着你本来就不知道这有个陷阱后者很大可能意味着你不知道怎样解决。学习C理论者的方法在上面写了那么多之后怎样学习C这个问题的答案其实已经很明显了。我们所欠缺的是一个书单。第一本假如你是一个C程序员那么很大的可能性你会需要用到底层知识硬件平台架构、缓存、指令流水线、硬件优化、内存、整数浮点数运算等这是因为两个主要原因一解析底层知识有助于写出高效
36、的代码。二C这样的接近硬件的语言为了降低语言抽象的效率惩罚在语言设计上作了很多折衷比方内建的有限精度整型以及浮点型比方指针。这就意味着用这类语言编程容易掉进Joel所谓的“抽象破绽需要你在语言提供的抽象层面之下去考虑并解决遇到的问题此时的底层知识便能帮上大忙。因此一本从程序员而不是电子工程师的角度去介绍底层知识的书会非常有帮助这就是推荐?ComputerSystemsAProgrammersPerspective?以下简称CSAPP中译本?深化理解计算机系统?的原因。第三本是的第三本另一方面C不同于C的一个关键地方就在于C在完全保存有C的高效的根底上增添了抽象机制。而所谓的“当代C风格便是倡导
37、正确利用C的抽象机制以及这些机制构建出来的当代C库以STL为代表的Bjarne也很早就倡导将C当作一门不同于C的新语言来学习就拿内存管理来讲使用当代C的内存管理技术几乎可以完全防止new以及delete因此一本从这个思路来介绍C的入门书籍是非常必要的这就是推荐?AcceleratedC?的原因以下简称AC。?AcceleratedC?的AndrewKoenig是C标准化经过中的核心人物之一。第二本C是在C语言大行其道的历史背景下开展起来的在一开场和后来的相当长一段时间内C是C的超集所有C的特性在C里面都有因此导致了大量后来的C入门书籍都从C讲起实际上这是一个误导因为C固然是C的超集然而用抽象机
38、制扩展C语言的重大意义就在于用抽象去覆盖C当中裸露的种种语言特性让程序员可以在一个更自然的抽象层面上编程比方你不是用int*加一个数组大小n来表示一个数组而是用可自动增长的vector比方你不是用malloc/free而是用智能指针以及RAII技术来管理资源比方你不是用一个只包含数据的构造体加上一组函数来做一个暴露的类而是使用真正的ADT。比方你不是使用second-class的返回值来表达错误而是利用first-class的语言级异常机制等等。然而C毕竟是C的源头剥开C的抽象外衣底层仍然还是C而且更关键的是在实际编码当中有时候还确实要“C一把比方在模块级的二进制接口封装上。Bjarne也讲过
39、OO/GP这些抽象机制只有用在适宜的地方才是适宜的。当人们手头有的是锤子的时候很容易把所有的目的都当成钉子有时候C确实可以提供简洁高效的解决方案比方C标准库里面的printf以及fopen此例受云风的启发的使用界面就是典型的例子。简而言之理解C语言的精神不仅有助于更好地理解C更理性地使用C而且也有其理论意义这就是推荐?TheCProgrammingLanguage?以下简称TCPL的原因。此外建议在浏览?AcceleratedC?之前先浏览?TheCProgrammingLanguage?。因为一?TheCProgrammingLanguage?非常薄。二假如你带着比拟的目光去看问题看完?Th
40、eCProgrammingLanguage?再看?AcceleratedC?你便会更深入的理解C语言引入抽象机制的意义以及实际作用。第四本?AcceleratedC?虽然写得非常漂亮但正如所有漂亮的入门书一样它的优点以及弱点都在于它的轻薄短小。短短3百页对当代C的运用精神作了极好的概述。然而要纯熟运用C我们还需要更多的讲解这个时候一本全面但又不钻语言牛角尖从“语言是怎样支持抽象设计的角度而不是“为了讲语言特性而讲语言特性的角度来介绍一门语言的书便至关重要在C里面我还没有见到比C之父本人的?TheCProgrammingLanguage?以下简称TCPL做得更好的C之父本人既有大规模C运用的经历
41、又有语言设计思想的最本质把握因此TCPL才能做到高屋建瓴不为细节所累同时又能做到理论导向不落于为介绍语言而介绍语言的巢臼。最后有一个需要提醒的地方TCPL其实没有它看起来那么厚因为真正介绍语言的内容只有区区500页第一局部根底第二局部抽象机制和第四局部用C设计剩下的是介绍标准库的可以当作Manual参考手册。建议3CSAPPTCPLACTCPL。是的在C方面登堂入室并不需要浏览多得恐惧的所谓“经典至于为什么这些“经典无需浏览前面已经讲的很详细了。其实你只需要这四本书就可以奠定一个深沉的根底和对C的成熟理性的当代运用理念。其余的书都可以当成参考资料用到的时候再去翻阅即建议4理论驱动地学习。理论驱
42、动当然不代表什么根底都不打直接捋起袖管就上。不管运用哪种工具首先都需要知道关于它的一定程度的根本知识包括应该怎么用以及不应该怎么用。知道应该怎么用可以帮你发挥出它的正确以及最大效用知道不应该怎么用那么可以帮你防止用的经过中伤及自身的危险。这就是为什么我建议你看四本书和建议你要解析C中的陷阱大局部来自C因此你可以浏览?C缺陷以及陷阱?的原因。理论驱动代表着一旦一个扎实的根底具备了之后获得延伸知识的方式。出于环境以及心理的原因C学习者们在这条路上走错的几率非常大许多人乃至以上来就拿EffectiveCMoreEffectiveC、InsideCObjectModel这类书去读是的我也是所以我才会在
43、这里写下这篇文章结果读了一本又一本出现知道虚函数实现机制的每个细节却不知道虚函数作用的情况。理论驱动其实很简单理论查文档。知识便在这样一个简单的循环中积累起来。理论驱动的最大好处就是你学到的都是理论当中真正需要的属于那“80%最有用的。而查文档的重要性前面已经讲过了但对于C理论者来讲哪些“文档是非常重要的呢第二本?CCodingStandard?。无需多作介绍这是一本浓缩了C社群多年度来珍贵的经历结晶的书贴近理论处处以80%场景为主导不钻语言旮旯用本为主总之非常值得放在手边时时参阅。因为书很薄所以也不妨先往脑袋里面装一遍。书中的101条建议的介绍都很简单并且指出了详细介绍的延伸浏览在延伸浏览的
44、时候还是要注意不要陷入无关的细节以及不必要的技巧中时时抬头看一看你需要解决的问题。在C编码标准方面Bjarne也有一些。第一本?ThePragmaticProgrammer?用本程序员的杰作固然不是一本C的书但其介绍的理论理念却是所有程序员都需要的。第三本?CodeComplete,2ndEdition?这是一本非常卓越的参考资料涉及开发经过的全景有大量珍贵的经历。你未必要一口气读完但你至少应该知道它里面都写了哪些内容以便可以回头参阅。其它所有优秀的技术书籍都是资料来源。一旦养成了查文档的习惯所有的电子书、纸书、网络上的资源实际上都是你的财富。不过查文档的前提是你要从手边的问题分析出应该到什么
45、地方去查资料这里分析问题的才能很重要因此建议5考虑。这个建议就把我们带到了第四本书第四本?你的灯亮着吗?。不作介绍自己浏览这本书只有一百多页但精彩非常妙趣横生。最后要想理性地运用一门语言不仅需要看到这门语言的特点还要可以从另一个角度去看这门语言即看到它的缺点因为从心理上事实10一旦我们熟悉了一门语言之后就容易不知不觉地在其框架下考虑受到语言特性的细节的影响作出second-class的设计。对于像C这样的在抽象机制上作了折衷的语言尤其如此考虑容易受到语言机制本身细节的影响往往在心里头还没想好怎么抽象就已经确定了使用什么语言机制乃至技巧更有甚者是为了使用某个特性而去使用某个特性。然而实际上我们应
46、该建议6脱离语言考虑使用语言实现。关于设计的一般理念EricRaymond在?TheArtofUnixProgramming?的第二局部有非常精彩的阐述。此外除了脱离语言的详细抽象机制来考虑设计之外学习其它语言对同类抽象机制的支持也是非常有益的正如老话所讲“兼听那么明。前一阵子reddit上也常出现“HowLearningXXXhelpmebecomeaBetterYYYprogrammer其中XXX以及YYY指代编程语言的帖子正是这个道理这就把我们带到了最后一个建议学习其它语言。建议7学习其它语言。假如你是一个系统程序员你可能会觉得没有必要学习其它语言然而未必如此你未必需要精通其它语言而是可
47、以去试着解析其它语言的设计理念是怎样支持日常编程中的设计的。这一招非常有利于在使用你自己的语言编程时心理上脱离语言机制细节的影响作出更好的抽象设计。尾声建议8可选重读本文。注这篇文章的目的是给国内的C学习者尤其是初学者一个可操作的建议。我打算不断修订并完善它因为这是根据我个人的经历来写的而基于我对C的熟悉程度可能会有地方并不能完完全全站到初学者的视角来看问题。我估计会有这样的地方所以假如有任何建议请发邮件给我del.icio.us标签:-1.已确认feedburner不可靠由于全文输出之后feed庞大到了近1M所以出现严重乱码CSDNblog的后台编辑器对庞大的feed也有奉献导致了大量的格式化tag遂从这篇开场用LiveWriter写blog输出的文本含有的格式化tag消失了。Anyway费事用FB订阅的同学转为直接订阅原始rss因feedsky抓取feed似乎也似乎时有问题2.C的罗浮宫已改为全文rss输出。3.AsAlways欢送参加我们的讨论组自从8月份建立以来我们已经吸引了三百位同学二千五百多条讨论想知道我们讨论些什么参见TopLanguage讨论参加前。本blog相关文章fromtag