Code Style
代码的风格
1. 简介
2. 什么是风格?
3. 代码的风格为什么如此重要?
4. 更少的工作,更多的文档?
5. 推荐的代码风格
6. 简单的文档
7. 输出风格
8. 结论
简介
让我们面对一下吧…如果您是一个资深的程序员,那么您总是在最后期限下工作并且您的最终目标是完成您设计的软件。如果您是个新手,您的努力是更多的研究、试验、当然还有错误和一心希望您的程序可以象打算的那样运行。不管怎样,当您的程序真的如愿以偿的运行时那种成功的感觉令人十分振奋,但更多的程序员发现能够用良好的风格生成程序内部代码时的那种自豪的感觉更棒。
如果您是程序设计小组的成员或者如果您还在书写学校分配的任务,那么您会有机会被要求遵守某些必须遵守的风格规则。 绝大多数的程序员考虑风格这件事就象一个10岁大的孩子看待就寝时间一样。但资深程序员和我所见过的小组领导及多年来使用许多风格的程序员都会试图向您传达良好的代码风格与您所得意的一些书写代码的技巧同样重要。在这篇文章中我将尝试包括一些输出风格的观点,这也许有助您的编程旅程。
更少的工作,更多的文档?
因此风格意味着要在代码的每一行加上注解,对吗?错。如果没有做对的话,注解也会变成一场灾难。 我仍然希望一个程序员学会喜欢输入注解或真正对注解有足够的重视。为了未来的可维护性必须强制自己正确的放置注解。所以怎么能够不使用注解?
显然对一个新手最困难的事是懂得什么是好的变量命名。让我们看看以下的代码。您能告诉我下面的代码是做什么的吗?
float __fastcall TExampleForm::CalcAverageGrade(void) { int y=0; int i=0; for (i; i<x; i++) { y=y+g[i]; } return float(y/x); }在上面的例子中,您能很轻易的告诉我y代表什么呢?x又是什么呢?这段代码也许需要一些注释来解释这些变量的代表意义及代码中发生了什么?应用以上的代码风格,看不出什么逻辑关系。现在让我们看看应用更好的代码风格以后,代码是何等模样?
float __fastcall TExampleForm::CalcAverageGrade(void) { int total=0; for (int i=0; i<maxGrades; i++) { total+=Grades[i]; } //求所有成绩的和 return float(total/maxGrades); } //计算平均成绩在您除错时以上两段代码孰优孰劣,已不必多说。现在就让我们讨论一些能够让您的代码更具有可维护性的推荐风格吧。
推荐的代码风格
1. 使用有描述意义的变量名。
2. 使用i, j, k, l, m作为循环计数变量。这起源于Fortran,自始自终这都是事实上的工业标准。
3. 在闭合括号处为所有的声明和方法注释。这样在尝试找到与此配对的上一个初始括号时更容易做决定,尤其在声明很长时。
4. 考虑将if后面或循环定义体的初始括号放在一个单独的行上。这真的有助于您找到与其对应的闭合括号。
5. 使用适当的组合运算符 (+=, *=, 等等)。对自增(自减)变量使用++ 和 -–运算符。正确使用这些运算符会使您的代码更可读和更一致。这也减少了输入的字符数量。组合运算符也会帮助编译器生成更快的代码。举例来说,i++产生的asm(汇编)代码是inc [i],而i=i+1将会产生如下的asm(汇编)代码mov eax,[i] inc eax mov [i],eax。
6. 注解代码时,要明智些!如果一段代码的逻辑关系很复杂,注解将有助于别人理解代码的意图。但如果逻辑关系直线向前,避免加上并非必须的注解。要象维护您的代码一样维护您的注解!
7. 命名变量时,使用有描述意义的大写。简单变量(例如,int, long, String)应该以小写字符开始。复杂变量(例如,对象、结构、数组)应该以大写开始。变量名称中包含的所有单词都应该大写开头。这会让读(写)代码的人对所访问的数据类型有一个清晰的第一印象。
8. 避免在变量名中使用下划线。绝大多数的编译器中,它都有特殊的意义。
9. 尽可能(而不是疯狂的)将代码模块化。合理的话,将代码放入函数中去。这允许更好的代码重用性和可读性。
10. 使用正确的循环。如果代码最少要执行一次,使用do-while循环,否则使用while-do循环。如果确切的循环执行次数已知,使用for循环。
11. 在事件发生的数量超过两种时,只要可能就使用switch声明。同时,无论何时只要可能就包含一个switch default(缺省开关),这样总会有一个选项被触发。Switch声明很容易除错,而且比组合的多重if声明执行速度更快。
12. 在您代码中的逻辑步骤之间加上一个空行(例如,定义变量、循环、等等)。
13. 声明变量的位置非常重要。变量应该声明的位置几乎没有随意性。当变量用于整个(类)对象或者必须在对象外可见的时候,变量应放在头文件中。临时变量如果不需要在if声明或循环体外被访问的话,就应在它们内部声明。不正确的放置变量声明会导致执行速度减慢、错误、或者引起误导的代码。
14. 初始化所有的变量。
15. 如果您有非空返回(带返回值)的函数,确保所有的退出点都使用了return。对编译器产生的警告"function should return a value"(函数应该返回一个值)要引起足够重视。这是严重警告并且可能导致您的软件发生随机错误。
16. 在两个不同类型的变量间赋值时,应对变量进行强制转换计算来避免编译器的警告(例如:int x; float y; … y=float x;)。这么做可以防止"Conversion may loose significant digits"的警告。作为一个程序员您的目标应该尽可能的减少警告的数量。而强制类型转换将消除其中的大多数。
17. 永远在删除后将指针设为NULL。
18. 尽量仔细的调查以避免“闭门造旧车”。经过证明的函数与程序使用时优先于新写的代码。这会让您有更多的时间去写真实的逻辑代码并且非常有助于维护。尽管尽管动态链表的书写非常有趣,它早已被完成了!
19. 正确的拼写很重要。如果拼写有错的话,将来的搜索会很困难。
20. 永远不要使用两个只有大小写不同的变量名字。
21. 在您创建代码时就输入注解,而不是以后。在您修改代码的时候,保持对注解的维护。
22. 如果您在调试或除错时注解(rem)了一段代码的话,确保您最后将被注解的代码删除。
23. 最后最重要的是…保持风格的一致。
简单的文档
平凡的文档在创建一个可维护的系统是却十分有效。您应该设置一个标准来为您的文档注解模板规定文件的开始处应该放置的内容。这里是某些应该在您的模板中完成的东西:
1. 原创作者名字
2. 原始创建日期
3. 文件的用途
4. 包括使用指导在内的主要内容列表
5. 包括修订日期的修订历史记录。同时应该说明修订时发现并修复的bug。
文件注解应该放在文档头部,并尽量简明。下面是我们现在的应用程序的一个例子。这个例子比较复杂。
/*
Written by(作者): Scott Cross
Date originally Completed(原始完成日期): 9/18/99
Purpose(用途): Main routine for NY Billing. This logic calculates the installments and provides all data necessary to print, display, and report billing status. The form will display the billing information. The main structure, InvoiceInfo, has all information including detail of Installments and Payment activities. Although the main object is a form, the form need not be shown in order to get billing information. This is the only billing logic for this version of the system. All billing inquiries should go through this routine.
Usage(用法): Nothing will be performed during the OnCreate event with the exception of setting some reference variables. All calculations are done by calling the main routine LoadAcctInfo. This routine can be called many times for different policies since it is fully initialized on each call. There are 5 parameters for the main functions and their usage is as follows:
bool LoadAcctInfo(
String policyNo - Supplies the logic with the targeted PolicyNo. bool printInvoice - Set to true if you want to print the invoice. bool nightRunning - If being called from the night, set to true. bool payableRunning - If being called by accounting rpt, set to true. String masterPrintDate - This is a date. For more info on usage, see cpp. );
No preliminary logic needs to be performed and the function will return true in most cases. No structures are passed since the main structure is public. It is imperative that the LoadAcctInfo be called prior to displaying the screen or unexpected results can occur since the main structures will not be initialized.
struct InvoiceInfoStruct{ PaymentHistoryStruct Payments[30]; - Payment History int paymentCount; - Count of Payments InstallmentStruct Installments[30]; - Installment Information int installmentCount; - Count of Installments int currInstall; - The current due installment float totalPaid; - The total paid on file * float totalDue; - Total due on file float pastDue; - Total amount past due float totalBilled; - Total amount billed on file float totalApplied; - Amount applied to installments ** String equityDate; - The date the premium is paid to String dateDue; - Date the file is due a payment float annualizedPremium; - the annualized premium *** };
* Restricted to masterPrintDate** Should equal total paid*** What the annualized premium is for the policy as stored in the tables if rated for one year.
Update History(更新历史):09/18/1999 - Scott - Completed02/01/2000 – Scott - Fixed totalPaid error on cancelled file*/
输出风格
输出风格没有标准。在我的观念中,编程最精彩的部分是程序的设计。您可以有自己的选择,从什么是好的或坏的直到系统的外观和感觉。尽管如此,仍有些有助于您的设计的建议。
1. 选择统一的字体。
2. 把界面设计成可以在不同分辨率和不同设置下正常工作。启用/不用大字体,然后测试您的软件。并假定用户仍在windows的VGA设定下运行(640X480 16色)。
3. 在多种颜色方案下测试软件。
4. 尝试维护逼真的3D效果。大多数情况下,初始的form(页面)应该是凸起的并带有一种附加的下凹效果。尽管这看起来有点小儿科,但这使得程序有了深度并非常有助于分割页面。
5. 牢记输出效果的性能。在处理器集中的循环中,更新越简单,执行就越快。
6. 尽量避免在界面中使用太多的噱头组件和效果。这会给人不专业的感觉,也可能伤害用户的信心,除非工程要求浮华的设计。
7. 设计登录屏幕,让用户无须鼠标动作就可以获得更多。
8. 您的用户也许欣赏毫不杂乱的环境,但也要牢记这依靠用户的配置,多屏可能会使系统太慢。尝试在速度和可用性之间找到平衡吧。
9. 在任何时候使用弹出提示和提示条都是合适的。从一开始就就记住要将页面设置成这样的。
10. 向导类型的界面对复杂的多步骤过程时十分合适。这使得软件可以指导用户一步步的走过这些步骤。找一个好的NoteBook(笔记本)组件吧。
11. 在进行长时间的操作时,应该总是调用Application->ProcessMessages();保持界面更新并让windows知道您的应用程序仍然处于活动状态且能够响应消息。
12. 最后最重要的是…保持系统风格的一致。
结论
编程的风格要比许多程序员想像的更重要的多。您想让别的程序员看见您现在的工程中的代码吗?您是不是对您的代码和您的系统一样自豪呢?现在花点时间来决定想在您的代码中采用何种风格并开始每天使用这种风格。记住,用6个星期来发展一个习惯,不管它是好的还是坏的。
祝 好运!
原著: Scott Cross
翻译: cker
版权说明:
国内的网站上,有许多关于C++Builder的内容,但多以软件、组件为主。论坛里也大都不能令人满意,很空虚的感觉。书籍又都昂贵,内容却有抢钱之嫌。对银子不足的初学者、自学者关爱不够,因而想尽自己的绵薄之力。
文中的所有资料都是从国外网站上收集而来。因为E文不方便,所以翻成中文。又因为English和计算机都不是非常好,文中的错误在所难免。若大家觉得有用的话,我计划不断搜集翻译一些有用的东西。
有任何意见和建议请mailto:cker@sina.com
您可以随意复制、分发、下载此文档。但未经本人同意,您不可以截取、改动本文片断,或用本文谋取任何形式的利益。
史平洋
2001.2