编程高手之独孤九剑

jaminwm
博客专家认证
2002-07-03 02:14:08
作为一个程序员,现在的编程工具比以前有了长足的进步,可 是最好的编程环境也无法帮助一个糟糕的程序员,相反,一个优 秀的程序员可以克服一种不良语言或者一个劣质的操作系统带 来的坏影响。编码不仅仅是编码,我们必须评价各种折中方案,在许 多的可能性当中做出选择、排除错误、做测试和改进程序性能,还 要维护自己或他人写的软件。那我们怎么才能顺利完成工作,写出 更好的代码呢?

  在工作中我相信大家和我们一样,遇到过各种问题:因为不能 理解而重写一个程序、对一个错误的算法浪费了许多时间编程,需 要让一个程序运行速度快3倍而且使用更少的内存等等。这些问题 产生的原因是它们是实际的问题,没有教科书来讲这些实际的问 题,只能在实践中慢慢的增长经验。本文参考了一些其他书籍,结合 自己在工作中的一些经验和教训,希望能起到一个抛砖引玉的作 用。下面分几个方面来讨论编码实践中的问题。

  代码应该简短、清楚并讲述了所发生的一切。但是有很多程序员患有"程 序设计语言综合症",症状主要表现为,拒绝写简洁清楚的代码,却使用具有技巧的、 比较精练的、异乎寻常的编码方法。请看如下代码:

return ((uCur<=1)?(uCur?0:1):(uCur==4)?2:(uCur+1));

  程序员把自己无穷尽的创造力用到了不合适的地方,我们的目标应该是写出最清晰 的代码,而不是最巧妙的代码。我见过的最长的类似代码是这样的,如果你在他写的语 句上按一个End键,那么在屏幕上,你将只能看到这行代码的后面的部分,其他的代码 都看不到了。请记住,我们的用户有两类,一类是使用代码生成的程序的用户,一类是 维护我们代码的人员。代码的简洁清楚和可读性再怎么强调都不过分。

  下面讨论的问题都是一些小的细节的问题。在整个编程过程中,时刻注意这些细节 问题对程序的最后质量和维护性都产生很大的影响。


布局法则

  源程序代码的规划和布局是一个计算机编程的美学问题。组织得很好的代码无论从 直观上还是内心中都能给人一种愉悦的感觉,而且也使人很容易的理解代码、检查代码, 日后的维护也很方便。对于布局来说,大部分工作是为了使人能够读懂程序,一小部分 是为了计算机读懂程序。那么布局的价值在哪里呢?

  Chase和Simon在他们的那篇著名的论文"Perception in Chess"中,对新手和专业棋手的记忆残局的能力进行了比较和研究,当把比赛中可能出现的残局摆在棋盘 上时,专业棋手的记忆力要远高于新手。而当棋子随便放时两者的水平差不多。几年后, Ben Shneiderman在计算机编程方面的研究得出了与Chase和Simon 相同的结论。在他们的论文"Exploratory Experiments in Programmer Behavior"中,Shneiderman发现当把程序语句有规则安排时,专业程序员对程序的记忆比新手好。这些发现在别的 领域如围棋、电子、音乐等方面都得到了证实。

  上述研究表明结构化可帮助有经验的程序员想像、理解和记住程序的重要特性。

  看看下面的代码布局:

for (n++;n<100;field[n++]='\0');*I='\0';return('\n\);

  再看看格式化后的布局:

for (n++;n<100;n++)

field[n]='\0';

*I='\0';

return '\n';

  两者的对比是明显的。那么格式化的原理和标准是什么呢?


布局的基本原理

  格式化的基本原理是用直观的布局显示程序的逻辑结构。

★ 正确表达出程序的逻辑结构

★ 自始至终地体现代码的逻辑结构

★ 提高可读性

★ 易于修改

  正确的表达出程序的逻辑结构是结构化的基本原理,是编写好的布局的最直接的目的。一般采用缩行和空格来 标明程序的逻辑结构。一个好的布局风格应该可以体现大多数的逻辑结构,而且这种布局应该是使代码容易读。另 外,对于一个好的布局,修改一行代码不需要涉及其他的语句。


布局技巧

1) 空格

  空格包括空格、制表符、断开和空行。通过它们,可以很好的显示程序的结构。Gorla和Benader的研究发现, 一个程序中的空行数目最好占8%-16%。

2) 缩排

  当一个语句在逻辑上从属于上一个语句时,这个语句就比上一行退几格。在"Program Indentation and Comprehensibility"这篇论文的研究表明,当程序缩排 是2-4个空格时,程序的理解度要上升20%-30%。比如:

while PixelColor=RedColor do

begin

statement1;

statement2;

. . .

end;

3) 对齐

  对齐是指把同属性的语句对齐。

4) 分组

  用空行来把有关的为完成某任务的语句组织在一起。

5) 括号

  对于混合使用运算符时,由于它们的优先级的原因,即使不必要,多写几个括号也是好主意。在巨人公司工作 的时候,有一个打印的程序,结果总是不对,后来发现是一个表达式不对,就是因为运算符优先级的问题,本来想 移2位,结果移了64位。因此,尽管括号不是非用不可,但是用了可以使代码具有良好的可读性,和避免逻辑错误。

  看看下面两个语句的对比:

a) leap_year = y%4 == 0 && y % 100 !=0 || y % 400 == 0;

b) leap_year = ((y%4==0)&&(y%100!=0)) || (y%400==0);


  布局首先要考虑的是如何显示程序的逻辑结构,第二个原则是好看。标准有: 准确、连续、可读、易维护。如果达到了这些,而且程序也好看,那么布局就算成功了。



数据名称的命名法则

  程序中名字是很重要的一方面,名字用来标志一个变量或函数。如何命名它呢?首先考虑的问题是变量的名称 是否完全而又准确的描述了变量所代表的实体。一个恰当的名字说明的往往是"什么"而不是"怎样"。

  一个名字应该是简练的、容易记忆的。比如NumPending,uTotal,UserIndex等。最好在后面再加一 些简短的注释如:int upending=0;// current length of input,这样代码的可读性大大增加。但是一味的全部采用长名字也不可取,这样会降低清晰性。一般 我们采用的是,全局(包括类中的)变量用长名字,局部变量用短名字。比如:

for(ThisIsLoopVarForRow = 0 ; ThisIsLoopVarForRow<NumberOfRow; ThisIsLoopVarForRow++){>P ALIGN="JUSTIFY"> // do something

};



for (uRow=0;uRow<NumRow;uRow++){>P ALIGN="JUSTIFY"> // do something;

}

  显然,后面的代码要清晰的多。

  在程序界,查尔斯-西蒙尼(Charles Simonyi)这位软件史上的传奇人物,他的一篇关于"匈牙利命名法" 的博士论文中的命名约定被普遍采用。查尔斯.西蒙尼(Charles Simonyi)是"所见即所得(What You See Is What You Get)"的发明人,这是微软赖以独霸天下的Windows系统的核心,查尔斯-西蒙尼还一手建立了微 软的程序员管理体系,他在微软公司的头衔是首席建筑师(Chief Architect),是微软最高智囊团的核心。Word,Excel等微软的应用软件都是在他的领导下开发成 功。

  "匈牙利"命名约定,是通过在数据和函数中加入额外的信息以增进名字的可读性。例如:

char ch; /*所有的字符变量均以ch开始*/

byte b; /*所有的字节变量均以b开始*/

long l; /*所有的长字节变量均以l开始*/

对于指针,一般在前面再加一个p:

char *pch; /*指向ch的指针以p开始*/

byte pb; /*指向byte的指针以p开始*/

  函数和数组的命名遵循同样的约定,名字由相应的返回类型名开始,后面跟一个描述的名字。例如:

char chLastKeyPressed;

void *pvNewBlock(size_t size);

void *pvResizeBlock(void *pv, size_t sizeNew);

  采用"匈牙利"约定的好处是明显的。例如,当你在程序中看到有一个以pch开头的变量,不用查看声明就立 即知道它是一个指向字符的指针。

  如果读者对"匈牙利"命名法的详细内容感兴趣,可以参考其他书籍,限于篇幅这里就不详细说明了。


注释的使用法则


  每一种编程语言都提供了注释的功能,注释可以帮助自己或者别人更好的理解程序,但是如何写注释也有一些 问题。看看下面这个注释:

/* Initialize "total" to "number_received" */

node->total = node->number_received;

  这个注释应该删除,对于明显的东西没有必要画蛇添足。 应该注释那些不能一下子看明白的东西,说明一些难以琢磨的事情。 在巨人工作的时候,我经常在代码中看到类似的注释:

Some code here ; /* zjm 修改了这个语句 */

  我们从注释中看到了什么呢?除了知道有一个叫zjm的人改过此代码以外,就没有什么了。这种注释写了等于 没有写。应该说明为什么原来的代码应该修改,以及做了什么修改,原来的代码也不要删除,应该注释掉并且说明。

  如果你觉得一段代码需要大段的注释来解释它,那么你就应该好好考虑代码是否应该改进,对不好的代码,与 其费力的写注释,不如改写它。

  写注释的过程中,还有一点要注意,一定要保持代码与注释的一致性。 如果对代码做了修改,一定要修改相应的注释,并且最好保留原来的代码。如果注释与代码 相矛盾,只会把大家搞糊涂。如果保持代码和注释的一致性,就可以避免类似的问题。

  在程序编码中,我们经常会使用一些数,如各种常数、变换因子、用户定义的消息等等。 给这些数起一个名字,不要直接使用数字。请看下面的代码:

case ResvBuffer.MsgType of

0:MainICQForm.ResvLoginMsg;

1:LoginForm.ResvLoginMsg;

2:MainICQForm.ResvAllLinkFrindMsg;

3:MainICQForm.ResvAllLinkOnLineMsg;

4:MainICQForm.ResvFrindOnOffMsg;

28:if FindForm<>nil then

FindForm.ResvQueryFindMsg;

29:if ChatICQForm<>nil then

ChatICQForm.ResvCheckFindMsg;

30:if mp3shareForm<>nil then

mp3shareForm.ResvCheckFindMsg;

end;

  相信大家和我一样,看不出来这些数字代表的意义。只有写这段代码的人才知道,而且我打赌,过几个月后, 连他也不会记得这些数字
...全文
90 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复

2,948

社区成员

发帖
与我相关
我的任务
社区描述
就计算机等级考试、软件初、中、高级不同级别资格考试相关话题交流经验,共享资源。
c1认证c4javac4前端 技术论坛(原bbs)
社区管理员
  • 软件水平考试社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧