《编程精粹───Microsoft编写优质无错C程序秘诀.doc》由会员分享,可在线阅读,更多相关《编程精粹───Microsoft编写优质无错C程序秘诀.doc(185页珍藏版)》请在金锄头文库上搜索。
1、编程精粹Microsoft编写优质无错C程序秘诀Writing Clean CodeMicrosoft Techniques for Developing Bug-free CProgramsSteve Maguire 著姜静波 佟金荣 译麦中凡 校电子工业出版社目录序2某些背景4命名约定5引言7第1章 假想的编译程序11第2章 自己设计并使用断言19第3章 为子系统设防44第4章 对程序进行逐条跟踪67第5章 糖果机界面75第6章 风险事业91第7章 编码中的假象115第8章 剩下来的就是态度问题133后记 走向何方148附录B 内存登录例程152附录C 练习答案160参考文献183献给我的
2、妻子Beth,以及我的双亲Joseph和Julia Maguire为了他们的爱和支持序1986年,在为几家小公司咨询和工作了10年之后为了获得编写Macintosh应用程序的经验,我特意到Microsoft公司工作,参加了Macintosh开发小组。这个小组负责Microsoft的图形电子表格应用程序的开发。当时,我还不能肯定想象的代码是什么样子的,我想也许应该既引入入胜又雅致吧!但我看到的代码却很平常,与我以往见到的其它代码没有什么不同。要知道,Excel有一个相当漂亮的用户界面 它比当时其它基于字符的电子表格软件更容易使用,更加直观。但使我感受更深的是产品中包含的一个多功能调试系统。该系统
3、旨在自动地问程序员和测试者进行错误报警。其工作方式非常象波音747驾驶仓内向驾驶员报告故障的报警灯。该调试系统主要用来对代码进行监视,它并不过多地对代码进行测试。虽然现在该调试系统采用的概念已不再新鲜了,但当时它们的广泛使用程度以及该系统有效的查错能力还是吸引了我,使我深受启发。没过多久,我就发现Microsoft的大部分项目都有多功能的内部调试系统,而Microsoft的程序员都高度重视代码中的错误及其产生原因。在做了两年Macintosh Excel之后,我离开了该开发小组,去帮助另一个代码错误数目超常的小组。在开发Excel的两年中,我发现Microsoft虽然壮大了两倍,但许多老项目组
4、熟知的概念并没有随着公司的壮大而传到新项目组。新程序员不象我加入Microsoft之前时的老程序员一样对容易引起错误的编码习惯特别重视,而只有一般的注意。在我转到新项目组六个月之后,有一次我对一个程序员伙伴提到:“应该把编写无错代码的某些概念写成文字,使那些原理能在新项目组传开”。这时另一位程序员对我说:“你不要总是想着写文档,为什么你不把这一切都写下来?为什么你不写本书,问问Microsoft出版社是否愿意出版呢?毕竟这些信息不是谁的专利,其作用不过是为了使程序员更加重视错误。”当时我对这个建议并没有多想,主要原因是没有时间,而且以前我也没有写过书。以前我所做过与写书最有关系的事情,不过是在
5、80年代初协助别人主办Hi-Res杂志的程序设计专栏,这与写书毕竟不是一回事。正如您所见到的,这本书还是写出来了。理由很简单:1990年,由于错误越来越多,Microsoft取消了一个尚未公布的产品。现在,错误越来越多已经不是什么新鲜事情,Microsoft的几个竞争者都因此取消过一些项目。但Microsoft因为这种原因取消项目,还是头一次。最近,随着接连不断地出现产品错误。管理人员终于开始叫嚷“受不了啦”,并采取了一系列的措施企图将错误率下降到原先的水平。尽管如此,仍然没有人将这些错误因由记录下来。现在,Microsoft已经比我刚进公司时大了九倍。很难设想,倘若没有准确的指南,公司怎样才
6、能将出错率降低到原来的水平。尤其是在Windows和Macintosh的应用越来越复杂的情况下,更是如此。以上就是我最终决定写这本书的原因Microsoft出版社已经同意出版这本书。情况就是这样。我希望您会喜欢这本书,我力图使本书不那么枯燥并尽量有趣。Steve Maguire西雅图,华盛顿1992.10.22致谢我要感谢Microsoft出版社中帮助本书问世的所有人,尤其是在我写作过程中始终手把手地教我的两个人。首先我要感谢我的约稿编辑Mike Halvorson,他使我能够按照自己的进度完成了这本书,并且耐心地解答了我这个新作者提出的许多问题。我还要特别感谢我的责任编辑Erin OConn
7、or女士,她用了许多额外时间及早地对我写出的章节提出了反馈意见。没有他们的帮助,就不会有这本书。Erin还鼓励我以幽默的风格写这本书。她对文中的小俏皮话发笑当然不会使我不快。我还要感谢我的父亲Joseph Maguire是他在70年代中期把我引入早期的微机世界:Altair、IMSAI和Sol-20,使我与这一行结缘。我要感谢我于198183年在Valpar International工作时的伙伴Evan Rosen,他是对我职业生涯最有影响的几个人之一,他的知识以及洞察力在本书中都有所体现。还有Paul Davis,在过去的10年里,我与他在全国各地的许多项目中都有过愉快的合作,他也无疑的塑
8、造了我的思维方式。最后感谢花时间阅读本书草稿,并提供技术反馈意见的所有人。他们是:Mark Gerber、Melissa Glerum、Chris Mason、Dave Moore、John Rae-Grant和Alex Tilles。特别感谢Eric Schlegel和Paul Davis,他们不仅是本书草稿的评审者,而且在本书内容的构思上对我很有帮助。某些背景本书用到了一些读者可能不太熟悉的软件和硬件系统的名称。下面对其中最常见的几个系统给出简单的描述MacintoshMacintosh是Apple公司的图形窗口计算机,公布于1984年。它是最先支持“所见即所得”拥户界面的流行最广的计算机
9、。WindowsWindows是Microsoft公司的图形窗口操作系统。Microsoft公司1990年公布了Windows 3.0,该版本明显好于其早期版本。ExcelExcel是Microsoft公司的图形电子表格软件,1985年首次在Macintosh上公布,随后在进行了大量的重写和排错工作后,被移植到Windows上。多年来Macintosh Excel和Windows Excel共用一个名字,但程序所用的代码并不相同。在本书中,找多次提到曾经当过Macintosh Excel程序员这一经历。但应该说明的是,我的大部分工作是将Windows Excel的代码移到Macintosh E
10、xcel上或者是实现与Windows Excel相似的特征。我与该产品现在的惊人成功并没有特别的关系。我为Macintosh Excel所做的唯一真正重要的贡献是说服Microsft放弃掉Macintosh Excel,而直接利用Windows Excel的源代码构造Macintosh的产品。Macintosh 2.2版是第一个基于Windows Excel的版本,它享用了Windows Excel 80%的源代码。这对Macintosh Excel的用户意义重大,因为用了2.2版以后他们会感至Macintosh Excel的功能和质量都有了一个很大的飞跃。WordWord是Microsoft
11、公司的字处理应用软件。实际上,Word有三种版本:基于字符并在MSDOS上运行的 DOS版;Macintosh版;Windows版。到目前为止,这三种版本的产品虽然是用不同的源代码做出的,但它们非常相象,用户改用任何一个都不会有什么困难。由于Excel利用共享代码获得了成功,Microsoft已经决定Word的高版本也将采用共享代码进行开发。80x8680x86是MS-DOS和Windows机器常用的Intel CPU系列。680x0680x0是各种Macintosh所用的Motorola CPU系列。命名约定本书采用的命名约定和Microsoft所使用的“匈牙利式”命名约定差不多。该约定是由
12、生于匈牙利布达佩斯的Charles Simonyi开发的,它通过在数据和函数名中加入额外的信息以增进程序员对程序的理解。例如:char ch;/* 所有的字符变量均以ch开始 */byte b;/* 所有的字节均冠以b */long l;/* 所有的长字均冠以l */对于指向某个数据类型的指针,可以先象上面那样建立一个有类型的名字,然后给该名字加上前缀字母P:char* pch;/* 指向ch的指针以p开始 */byte* pb;/* 同理 */long* pl;void* pv;/* 特意显用的空指针 */char* ppch;/* 指向字符指针的指针 */byte* ppb;/* 指向字节
13、指针的指针 */匈牙利式名字通常不那么好念,但在代码中读到它们时,确实可以从中得到许多的信息。例如,当你眼看到某个函数里有一个名为pch的变量时,不用查看声明就立即知道它是一个指向字符的指针。为了使匈牙利式名字的描述性更强或者要区分两个变量名,可以在相应类型派生出的基本名字之后加上一个以大写字母开头的“标签”。例如,strcpy函数有两个字符指针参数:一个是源指针,另一个是目的指针。使用匈牙利式命名约定,其相应的原型是:char* strcpy(char* pchTo, char* pchFrom);/* 原型 */在上面的例子中,两个字符指针有一个共同的特点 都指向以0为结尾的C的字符串。因
14、此在本书中,每当用字符指针指向字符串时,我们就用一个更有意义的名子str来表示。因此,上述strcpy的原型则为:char* strcpy(char* strTo, char* strFrom)/* 原型 */本书用到另一个类型是ANSI标准中的类型size_t。下面给出该类型的一些典型用法:size_t sizeNew, sizeOld;/* 原型 */void* malloc(size_t size);/* 原型 */void* realloc(void* pv, size_t sizeNew);/* 原型 */函数和数组的命名遵循同样的约定,名字由相应的返回类型名开始,后跟一个描述的标签
15、。例如:ch = chLastKeyPressed;/* 由变量得一字符 */ch = chInputBuffer;/* 由数组得一字符 */ch = chReadKeyboard;/* 由函数得一字符 */如果利用匈牙利式命名方法,mall和reali可以写成如下形式:void* pvNewBlock(size_t size);/* 原型 */void* pvResizeBlock(void* pv, size_t sizeNew);/* 原型 */由于匈牙利式命名方法旨在增进程序员对程序的理解,所以大多数匈牙利式名字的长度都要超过ANSI严格规定6个字母的限制。这就不妙,除非所用的系统是几十年前设计的系统,否则这6个字母的限制只当是历史的遗迹。以上内容基本上没有涉及到匈牙利式命名约定的细节,所介绍的都是读者理解本书中所用变量和函数名称意义的必需内容。如果读者对匈牙利式命名约定的详细内