主题:发编程风格的牢骚
关于编写代码的一点建议。
笔者喜欢以C语言为基础的程序设计语言,比如说C/C++和JAVA。看到在论坛上有些代码的格式实在是有点让人看不下去,因此在这里,有一点关于C/C++/JAVA的代码编写的牢骚要发一下。注意,这篇文章是对初学C/C++/JAVA的初学者(像笔者这样的人)来说的,对于高手,当然不用以这篇文章为然。个人观点,仅供参考。
一、开发工具。
这里说的开发工具不是指针对某一种语言的IDE,而是指一个合适的编辑器和编译器而已。
工欲善其事,必先利其器。一个好的编辑器可以助你快速编写好代码。那么怎么样的编辑器才能算是一个好的编辑器?
首先,必定要有语法高亮显示!这一点非常重要。有了语法高亮显示,你写程序时就会少了许多的拼写错误。很明显,如果关键字的颜色或字体与常规文本不同的话,一旦出错了,那么马上就会发现。虽然在编译的时候也很容易发现这类错误,但是,与其把它留在了编译时才发现,为什么不在开头就把它给杜绝了好呢?更重要的是,要是你看到你辛辛苦苦编写的程序上在编译的时候,出现了一堆的错误,试问你还有没有兴趣继续看下去?当然,高手不会出现这种错误,但初学都会。初学者需要信心,所以,少些错误会有更好的效果。并且,不同的地方用不同的颜色,也是一种视觉的享受。
第二,要有自动缩进功能。为什么要缩进?下面有说明。自动缩进(尤其是智能缩进)会给你编程带来极大的方便,因为你不用每换一行都要自己手动缩进一次。
第三,对括号要有显示相应配对的功能。相信很多人都知道,当丢失括号的时候发生的错误,是非常让人恼火的。尤其是不正确的缩进格式或根本没有缩进的时候,如果少了一个大括号的话,要找到这个漏掉括号的地方,可能就要从头到尾再看N次代码了。并且,虽然正确的缩进格式可以找到这种错误,但是更保险的就是清楚每个括号跟谁是一对。况且,对小括号和方括号是否配对不是通过缩进就可以看到的。假如编辑器自动显示出与其配对的括号的话,这类错误就可以避免了。
第四,可以显示行号。在编译时出现问题,有了行号就可以快速定位了。
还有一些小功能也重要,但不是必须的,比如说支持自定义工具和热键等等。
综上所述,在笔者所用过的编辑器中,在Windows平台上最好的就是UltraEdit和Crimson Editor。这两个软件都满足上述的四点,而且还有一些贴心的功能。比如说Crimson Editor支持自定义热键调用程序。写完程序后,只要按设置好的热键,就可以对程序进行编译和运行,很方便。而UltraEdit是功能最强大的编辑器,也可以用自定义热键调用程序,但好像并不像Crimson Editor那么方便。最重要的是,Crimson Editor不用花银子去注册。在LINUX平台上,最好的是VI编辑器和Kate编辑器(绝没有贬低Emacs和其它编辑器的意思)。VI编辑器是用命令驱动的,非常便捷。而Kate,编辑器里嵌有Shell控制台,命令行编译很方便。事实上,LINUX是最合适的编程环境。要不是QQ没有LINUX版本的和还没有在Mandrake Linux解决中文输入的问题,笔者早就转到LINUX下了,毕竟LINUX不用花我太多Money。
在这里,笔者并不推荐初学者用IDE。为什么呢?虽然IDE的确可以帮助初学者进行编码,但还是有它的不足之处。拿VC++和DevC++这两个来比较,在使用DevC++时,要先熟悉DevC++环境,然后转到了VC++后,又要熟悉VC++,以后可能会学JAVA,又要学会像JCreator之类的IDE……那么为什么不使用统一的环境?更要命的是,IDE的编译命令是预先定好的,虽然可以通过改变选项实现不同的编译参数,但是又会有多少个初学者会这样做?只有自己动手输入编译参数,才能更快的掌握不同的参数的作用,并且具有更大的灵活性。实际上,听说很多高手都不是用IDE的。记住,你要学的是编程语言而不是IDE!当然如果你要用VC++生成什么界面的又不想自己编写代码的时候,另当别论。又或许有人会跳出来说,IDE里可以调试程序,而UltraEdit和Crimson Editor不能。的确,这两个编辑器没有内置的调试器,但可以通过适当的print语句实现,虽然不能实现多复杂的调试,但是初学者能去调试像Word这样的程序?
至于编译器,笔者一直用Borland C++ Compiler,免费的命令行那个,而JAVA就用j2sdk。LINUX下不用担心这个问题,因为Mandrake Linux里有许多种语言的编译器和解释器。不过,这个是看个人的需要的,像笔者根本不用C++设计有界面的程序,用BCC就够了,但是吃MFC饭的当然就要VC++了。
二、代码编写风格。
只有一个好的编辑器,并不能编写出好的代码,就像光有利器也不能善其事一样,必须更加注意自己编写代码的方法。代码有一个好的风格,不仅利于自己以后阅读,也有利于不同的程序员之间交流。一个软件编写代码时,没有一定的风格,那么这个软件就会很难读。不信你到网上拿一个风格错乱的程序来看,不用很长,就60行够了。如果你不整理的一下,就会体会到什么叫做“不忍卒读”了。笔者一看到缩进不明显的程序,就看都不想看了。
笔者认为一个好的风格,至少要具备下面的条件。
第一、在for、while、do、switch、case等等的后面,即使只有一个语句或者甚至是空语句,都要用“{”和“}”,并且要换行,“{”和“}”要对齐。这样做的话,一个函数体就很容易区分了,并且大括号不配对的问题也就很容易发现。而更重要的是,因为大括号是对齐的,可以从视觉上就把各个代码块和代码块之间的从属关系给区分出来。
第二、一定要有缩进,而且要明显!把缩进设为8个空格,不要多也不要少,刚好8个空格的空间!少了缩进不明显,多了浪费空间,影响视觉效果。在打完了开的大括号“{”后,马上换行把关的大括号“}”给打上去,然后再回到开的大括号后,换行,缩进,再编写大括号里面的代码,里面还有大括号的话,也依法照办。这样编写出来的代码,层次分明,易于阅读,也具有观赏性。
为什么强调是8个?用8个做为缩进的大小,可以控制你的代码的复杂度!不可思议吧?当你的缩进达到了四层或五层的时候,代码就显得很难看了。这时,就要考虑一下是不是应该把这部分给独立出来做一个模块了,从而减少代码的复杂程序。
第三、结对编程。“结对编程”是粱肇新先生提出来的,其基本思想就是一对的东西要同时出现,才不会出错。打完了“{”后马上换行打“}”,保证大括号配对,打开文件后马上关闭,然后才插入代码,这样就不会忘记关闭文件了。还有内存分配等等,都是这样。其实,不仅C/C++/JAVA里是这样,就连在QBasic等的里面也是这样,打完FOR后马上打NEXT,就不会出现FOR和NEXT不配对了。详细的过程请参考粱肇新先生的《编程高手箴言》。
第四,坚持少用GOTO语句。众所周知,GOTO语句会破坏程序的结构化程度,造成了程序难以理解。不信?试试下面的程序(这段代码是从《C和指针》里摘的。):
i = 0;
outer_next:
{
if(i >= NUM_ELEMENTS – 1)
{
goto outer_end;
}
j = i + 1;
}
inner_next:
{
if(j >= NUM_ELEMENTS)
{
goto inner_end;
}
if(value[i] <= value[j])
{
goto no_swap;
}
temp = value[i];
value[i] = value[j];
value[j] = temp;
}
no_swap:
{
j += 1;
goto inner_next;
}
inner_end:
{
i += 1;
goto outer_next;
}
guter_end:
{
}
怎么样?看出来了吗?这只是一个用冒泡法进行排序的程序而已!GOTO的危险可窥一斑!
第五、关于代码内容的想法。这点很多,也杂。笔者主要有四个方面要讲,一是标志符和运算符之间要有空格,这样看起来才容易看;第二,变量的声明问题,声明顺序要从简单类型到复杂类型按字典序排列,易于查找变量;第三,模块和模块间的接口要简单和统一。模块只需实现一个功能,接口处不要有太多参数,四个到五个已经是很多的了。最后,用自说明的变量名。还有像一些什么命令方法等的东西,参考其它的书去吧,它们更权威。在这一点上,实在很难说清楚,只有大家看多些优秀的代码和自己亲身做一下才会知道的。建议看K&R的《The C Programming Language》。
或许有人要问笔者,为什么要立这么多规矩来束缚自己?答案是正确的方法带来高效率和正确的结果。为什么有那么多的企业削尖脑袋要挤进CMM/CMMI的等级评定?因为“无规矩,无以成方圆”。规矩就像是一个冬天的火炉,当你习惯了没有火炉(规矩)的寒冬(无序状态),一个火炉(一套规矩)最初可能会让你觉得不舒服(绊手绊脚),但一旦你适应了这个火炉(规矩),它又会给你带来温暖(规范化的环境和高效率)。你不再会感到火炉的存在(规矩不再是一种约束),而且已经离不开火炉(没有规矩就会出乱子)。并且即使感觉不到它,但你不能去碰火炉(违反规矩),否则会烫到的(失去效率)。懂了吗?
总之一句,代码很可能只写一次,但肯定要看N次以上。
相信大家看到自己用规范的方法写出来一篇艺术品似的代码时,心里肯定会有一股成就感的。最后,说明一点,只有最适合自己的才是最好的。希望这篇文章能给大家带来一点好处,假如能做块引玉之砖就很好了。
林杰杰
LINSOSO@hotmail.com
2004-6-21
笔者喜欢以C语言为基础的程序设计语言,比如说C/C++和JAVA。看到在论坛上有些代码的格式实在是有点让人看不下去,因此在这里,有一点关于C/C++/JAVA的代码编写的牢骚要发一下。注意,这篇文章是对初学C/C++/JAVA的初学者(像笔者这样的人)来说的,对于高手,当然不用以这篇文章为然。个人观点,仅供参考。
一、开发工具。
这里说的开发工具不是指针对某一种语言的IDE,而是指一个合适的编辑器和编译器而已。
工欲善其事,必先利其器。一个好的编辑器可以助你快速编写好代码。那么怎么样的编辑器才能算是一个好的编辑器?
首先,必定要有语法高亮显示!这一点非常重要。有了语法高亮显示,你写程序时就会少了许多的拼写错误。很明显,如果关键字的颜色或字体与常规文本不同的话,一旦出错了,那么马上就会发现。虽然在编译的时候也很容易发现这类错误,但是,与其把它留在了编译时才发现,为什么不在开头就把它给杜绝了好呢?更重要的是,要是你看到你辛辛苦苦编写的程序上在编译的时候,出现了一堆的错误,试问你还有没有兴趣继续看下去?当然,高手不会出现这种错误,但初学都会。初学者需要信心,所以,少些错误会有更好的效果。并且,不同的地方用不同的颜色,也是一种视觉的享受。
第二,要有自动缩进功能。为什么要缩进?下面有说明。自动缩进(尤其是智能缩进)会给你编程带来极大的方便,因为你不用每换一行都要自己手动缩进一次。
第三,对括号要有显示相应配对的功能。相信很多人都知道,当丢失括号的时候发生的错误,是非常让人恼火的。尤其是不正确的缩进格式或根本没有缩进的时候,如果少了一个大括号的话,要找到这个漏掉括号的地方,可能就要从头到尾再看N次代码了。并且,虽然正确的缩进格式可以找到这种错误,但是更保险的就是清楚每个括号跟谁是一对。况且,对小括号和方括号是否配对不是通过缩进就可以看到的。假如编辑器自动显示出与其配对的括号的话,这类错误就可以避免了。
第四,可以显示行号。在编译时出现问题,有了行号就可以快速定位了。
还有一些小功能也重要,但不是必须的,比如说支持自定义工具和热键等等。
综上所述,在笔者所用过的编辑器中,在Windows平台上最好的就是UltraEdit和Crimson Editor。这两个软件都满足上述的四点,而且还有一些贴心的功能。比如说Crimson Editor支持自定义热键调用程序。写完程序后,只要按设置好的热键,就可以对程序进行编译和运行,很方便。而UltraEdit是功能最强大的编辑器,也可以用自定义热键调用程序,但好像并不像Crimson Editor那么方便。最重要的是,Crimson Editor不用花银子去注册。在LINUX平台上,最好的是VI编辑器和Kate编辑器(绝没有贬低Emacs和其它编辑器的意思)。VI编辑器是用命令驱动的,非常便捷。而Kate,编辑器里嵌有Shell控制台,命令行编译很方便。事实上,LINUX是最合适的编程环境。要不是QQ没有LINUX版本的和还没有在Mandrake Linux解决中文输入的问题,笔者早就转到LINUX下了,毕竟LINUX不用花我太多Money。
在这里,笔者并不推荐初学者用IDE。为什么呢?虽然IDE的确可以帮助初学者进行编码,但还是有它的不足之处。拿VC++和DevC++这两个来比较,在使用DevC++时,要先熟悉DevC++环境,然后转到了VC++后,又要熟悉VC++,以后可能会学JAVA,又要学会像JCreator之类的IDE……那么为什么不使用统一的环境?更要命的是,IDE的编译命令是预先定好的,虽然可以通过改变选项实现不同的编译参数,但是又会有多少个初学者会这样做?只有自己动手输入编译参数,才能更快的掌握不同的参数的作用,并且具有更大的灵活性。实际上,听说很多高手都不是用IDE的。记住,你要学的是编程语言而不是IDE!当然如果你要用VC++生成什么界面的又不想自己编写代码的时候,另当别论。又或许有人会跳出来说,IDE里可以调试程序,而UltraEdit和Crimson Editor不能。的确,这两个编辑器没有内置的调试器,但可以通过适当的print语句实现,虽然不能实现多复杂的调试,但是初学者能去调试像Word这样的程序?
至于编译器,笔者一直用Borland C++ Compiler,免费的命令行那个,而JAVA就用j2sdk。LINUX下不用担心这个问题,因为Mandrake Linux里有许多种语言的编译器和解释器。不过,这个是看个人的需要的,像笔者根本不用C++设计有界面的程序,用BCC就够了,但是吃MFC饭的当然就要VC++了。
二、代码编写风格。
只有一个好的编辑器,并不能编写出好的代码,就像光有利器也不能善其事一样,必须更加注意自己编写代码的方法。代码有一个好的风格,不仅利于自己以后阅读,也有利于不同的程序员之间交流。一个软件编写代码时,没有一定的风格,那么这个软件就会很难读。不信你到网上拿一个风格错乱的程序来看,不用很长,就60行够了。如果你不整理的一下,就会体会到什么叫做“不忍卒读”了。笔者一看到缩进不明显的程序,就看都不想看了。
笔者认为一个好的风格,至少要具备下面的条件。
第一、在for、while、do、switch、case等等的后面,即使只有一个语句或者甚至是空语句,都要用“{”和“}”,并且要换行,“{”和“}”要对齐。这样做的话,一个函数体就很容易区分了,并且大括号不配对的问题也就很容易发现。而更重要的是,因为大括号是对齐的,可以从视觉上就把各个代码块和代码块之间的从属关系给区分出来。
第二、一定要有缩进,而且要明显!把缩进设为8个空格,不要多也不要少,刚好8个空格的空间!少了缩进不明显,多了浪费空间,影响视觉效果。在打完了开的大括号“{”后,马上换行把关的大括号“}”给打上去,然后再回到开的大括号后,换行,缩进,再编写大括号里面的代码,里面还有大括号的话,也依法照办。这样编写出来的代码,层次分明,易于阅读,也具有观赏性。
为什么强调是8个?用8个做为缩进的大小,可以控制你的代码的复杂度!不可思议吧?当你的缩进达到了四层或五层的时候,代码就显得很难看了。这时,就要考虑一下是不是应该把这部分给独立出来做一个模块了,从而减少代码的复杂程序。
第三、结对编程。“结对编程”是粱肇新先生提出来的,其基本思想就是一对的东西要同时出现,才不会出错。打完了“{”后马上换行打“}”,保证大括号配对,打开文件后马上关闭,然后才插入代码,这样就不会忘记关闭文件了。还有内存分配等等,都是这样。其实,不仅C/C++/JAVA里是这样,就连在QBasic等的里面也是这样,打完FOR后马上打NEXT,就不会出现FOR和NEXT不配对了。详细的过程请参考粱肇新先生的《编程高手箴言》。
第四,坚持少用GOTO语句。众所周知,GOTO语句会破坏程序的结构化程度,造成了程序难以理解。不信?试试下面的程序(这段代码是从《C和指针》里摘的。):
i = 0;
outer_next:
{
if(i >= NUM_ELEMENTS – 1)
{
goto outer_end;
}
j = i + 1;
}
inner_next:
{
if(j >= NUM_ELEMENTS)
{
goto inner_end;
}
if(value[i] <= value[j])
{
goto no_swap;
}
temp = value[i];
value[i] = value[j];
value[j] = temp;
}
no_swap:
{
j += 1;
goto inner_next;
}
inner_end:
{
i += 1;
goto outer_next;
}
guter_end:
{
}
怎么样?看出来了吗?这只是一个用冒泡法进行排序的程序而已!GOTO的危险可窥一斑!
第五、关于代码内容的想法。这点很多,也杂。笔者主要有四个方面要讲,一是标志符和运算符之间要有空格,这样看起来才容易看;第二,变量的声明问题,声明顺序要从简单类型到复杂类型按字典序排列,易于查找变量;第三,模块和模块间的接口要简单和统一。模块只需实现一个功能,接口处不要有太多参数,四个到五个已经是很多的了。最后,用自说明的变量名。还有像一些什么命令方法等的东西,参考其它的书去吧,它们更权威。在这一点上,实在很难说清楚,只有大家看多些优秀的代码和自己亲身做一下才会知道的。建议看K&R的《The C Programming Language》。
或许有人要问笔者,为什么要立这么多规矩来束缚自己?答案是正确的方法带来高效率和正确的结果。为什么有那么多的企业削尖脑袋要挤进CMM/CMMI的等级评定?因为“无规矩,无以成方圆”。规矩就像是一个冬天的火炉,当你习惯了没有火炉(规矩)的寒冬(无序状态),一个火炉(一套规矩)最初可能会让你觉得不舒服(绊手绊脚),但一旦你适应了这个火炉(规矩),它又会给你带来温暖(规范化的环境和高效率)。你不再会感到火炉的存在(规矩不再是一种约束),而且已经离不开火炉(没有规矩就会出乱子)。并且即使感觉不到它,但你不能去碰火炉(违反规矩),否则会烫到的(失去效率)。懂了吗?
总之一句,代码很可能只写一次,但肯定要看N次以上。
相信大家看到自己用规范的方法写出来一篇艺术品似的代码时,心里肯定会有一股成就感的。最后,说明一点,只有最适合自己的才是最好的。希望这篇文章能给大家带来一点好处,假如能做块引玉之砖就很好了。
林杰杰
LINSOSO@hotmail.com
2004-6-21