“今天那个新加坡的叫兽讲的P2P还挺有意思的,”从报告厅出来,小P和老C走回教研室,小P一副很有心得的样子。
“是吗?我就一直和他的英语做斗争了,基本上没有听懂……都是华人,讲汉语好了……”
“哈哈,讲汉语怎么能体现国际水平,说不定人家还不会汉语呢。”
“就算讲英语,口音也不要那么重啊,我怎么听出一点唐山音呢?”老C有些不忿,“老美的我还是可以听懂的,英国人的可能差一些,不过也可以理解……”
“嘻嘻,你还没有听过印度人的英语呢……”
两个人一边走一边说笑,进了教研室。
“嘿嘿。”老C突然坏笑起来。
小P打了一个冷颤:“怎么了,这么吝的?”
“还记得周一我们的约定吗?”老C开始使坏,“我和你打赌,赌注是今天的晚饭。我赌周一的代码,你无法顺利的解释清楚……”
“切!”小P险些忘了这回事情,“刚好我中午吃得不多,你就准备好钱吧!”
“好,其实我早就想请你吃饭了!”老C拍拍口袋。
小P打开电脑,打开eclipse,找了一会儿,翻出那个a.c文件。“看,其实就是一个循环队列,很简单……”小P用鼠标在上面指指点点。
#include <stdio.h>
void main()
{
int a[20];
int b;
int m;
int k;
int N=20;
for(m=0;m<20;++m){
a[m]=1;}
m= 0;
b =1;
while(N>1)
{ if(a[m]!=0)
{
if (b==7){
a[m] = 0;
--N;
if (N==1)
{break;
}
b=1;
}
else{
++b;
}
}
++m;
m%=20;
}
for(k=0;k<20;++k){
if (a[k]==1)
{break;}
}
++k;
printf("%d\n", k);
}
“哦?是啊。”老C把椅子转过来,开始听小P介绍自己的代码,“我怎么忘了是数到几的倒霉孩子被踢出队伍了?”
“?自己出的题目都记不住?”小P开始翻看自己的代码,“应当是……嗯……也许……是,是数到7的被踢出!”
老C一脸坏笑:“您这个反映也太慢了吧?”然后他随便用笔点了一下屏幕,“请问这里为什么是 b = 1啊?”
“嗯,我看看……”小P一边看一边嘴里默念这什么,“先是初始化……然后,嗯,这个1代表在队列中……如果队里还有多于一个人……”这个时候小P恨不得运行一下gdb来单步跟踪一下自己的代码,“嗯,是这样的,哦,不对不对……”挣扎了一番后,小P很神气的说,“这里表示,如果一个小朋友被踢出队列,那么下一个小朋友应当数1!”
“呵呵,”老C笑道,“你的记忆力比我想象的好很多啊……”
“那是!”小P很是得意。
“那么我们来做个假设,”老C开始使坏,“如果现在幼儿园有25个孩子,结果是什么?”
“我看看,”小P开始改代码,“应当是……”
“如果是5个,30个或50个孩子呢?答案分别是多少?”老C不依不饶。
“哦,哦……”小P手忙脚乱的改代码,一次还因为忘了改for循环里面的结束条件,导致数组越界造成内存错误,查找了一番。
看到小P满头大汗的调试代码,老C有些不忍心了,“算了,算了,我就不和你争了,晚饭我请了!”
“哦?”小P高兴的抬头,“还是上次那一家?”
“呵呵,饭虽然我请你了,但是该说的话我还是要说的。”老C点点头,“你现在凭良心讲,这段代码写得如何?”
“嗯……”没有了晚饭的压力,小P开始认真考虑这个问题,“感觉确实不是很好,隔了一段时间看有种陌生的感觉……而且有点难调试,一时不知道应当怎么下手……”
“呵呵,你很诚实啊,”老C表扬小P,“这是做研发的态度!”他冲小P伸出大拇指,“很多人不愿意承认自己的问题呢,但是只有认识到自己的问题才可以进步啊,因此你不要害怕被别人踩,虽然有些话比较难听,但是只要道理是对的,你可以自动过滤掉感情倾向性的因素,认真体会每个批评的内涵吧。”
“嘿嘿,”小P顿时有了一种“生我者父母,知我者老C”的感觉。
看到小青年被自己揉捏的差不多了,老C说:“我们把这段代码打印下来,在纸上比较好圈圈点点……”
“好咧。”小P把代码打印出来,放到两个人面前。
“我们先不说代码,先说说你起的文件名称吧,a.c,这个名称……很……中性……不带任何感情色彩,当然也不带任何有用的信息……你刚才还是找了一番才找到的吧。”
“没有,我工程里面的文件并不多……”
“如果工程很多呢?我个人觉得我们是不是起一个带有强烈感情色彩的文件名更好呢?就算是main.c也比a.c强一些,起码你还知道自己的main()函数在哪个文件里面,而不用麻烦的使用IDE的search功能!”
“呵呵,我承认你说的有道理。”
“总的来说,这篇代码中存在很多的经典问题,但是我们目前只说代码的样子而先不谈代码的内容。”老C在纸上写下几行大字。
1. 前后统一
2. 缩进风格
3. 命名规范
“我们先来说说规范的事情,”老C说道,“希望你可以理解到规范的重要性。”他强调,“我们写代码是写给谁看的?是写给编译器看的吗?不,是写给人看的。我们是社会人,有别于自然人,需要遵守一定的规则,这样别人才可以预期你的行为,从而可以减少很多沟通的成本。”
“槑……”
“就比如交通吧,大家都靠右走,这样才可以顺利,如果哪个家伙在左边走,一定会引起不必要的麻烦甚至事故,这个是生活中规范的重要性,编码也是一样的。在编程行业内,有很多约定俗成的规范,你最好顺着它们来,因为它们都是经过检验的,行之有效的,可以避免很多低级错误的行为守则,这些守则我倒是知道一些,我会在以后和你慢慢讨论这些守则。”老C从他的桌子上拿过一杯水喝了一口,“下来我要和你说说排版的问题,严格说来,所谓排版或者缩进,没有规则,但一定要前后统一。”老C开始在纸上划拉起来,“你可以在一行开始缩进任何的空格个数或者使用tab健,但是,从你第一行代码到作后一行代码,一定要统一!”
“为什么?”小P不解的问。
“因为人总会有思维惯性,我们总是喜欢在熟悉的环境内生活或是工作,看代码也一样……如果你前后的风格统一,那么看代码的人心理压力会小很多,而且也更容易让人的注意力从格式上转移到代码内容本身,而不是总在想,该死,这里怎么突然多出一个空格!总之我们的心理作用,在进行注意力高度集中的智力活动时,总是喜欢简洁、整齐的环境,这样可以减少环境突然改变对注意力的影响。”
“哦,好像的确是这样,我在考试的时候,的确卷子越整齐,出错的概率就越小……”
“嗯,虽然理论上说只要保证你的代码缩进风格前后统一就可以了,但是在现实生活中我们不会也不允许千人千面,因为大家还是要互相交流的,让任何人去适应别人的缩进风格都是低效率和不公平的,因此形成了很多约定俗成的东西,哪怕它们不合理,但是它们的确形成了,而且你最好也遵守这样的规矩,如果你违背了这些东西,只能说明要么你是捣乱,要么你是绝对的新手。”
“哦?”
“这些有点像江湖黑话,如果你不是混江湖的,在打切口的时候闹了笑话,道上的兄弟一定会笑话你,新警察吧……”
“哈哈哈哈……”
“就我所知,目前江湖上有几种常用的黑话格式,K&R,BSD和GNU等,无论你采用哪一种,别人看了就知道你是道上混的,而且知道了你的山头,也就会高看你一眼……”
“是么?”
“是啊是啊,eclipse上面有黑话翻译器,你在Window->Preference的弹出窗口,找到C/C++分类,下面有Code Style子类,你点选以后在右边会出来一个下拉框,让你选择代码缩进风格,你可以试试,选择一个你觉得顺眼的,看看模板是怎么缩进的。”
“好啊,”小P在自己的电脑上捣鼓开了,“你选的是哪一个?”小P想跟着老C混一个山头。
“我选的BSD,因为比较向往那个学校……”老C答道。
“于我心有戚戚焉,”小P觉得这个理由很好,反正也没有什么质的区别,也就选了这个风格。
“下来你在Edit菜单下选择Format试试?”
“哦……嗯?真是不错啊。”
“你可以在Window->Preference中修改它的快捷键,只要自己觉得舒服就行。”老C补充到,“因为某些恶趣味,我改成了Alt+F8……哈哈。”
“囧。”小P没有理会老C的傻笑,自己又试了几下,“嗯,的确不错的。”
“好吧,我们再来说说命名规则,”老C喝了一口水,“这个就不像缩进那样有很明显的工具可以帮你翻译,但是也存在几个基本的帮派,而且这里面的斗争十分激烈,大家有争吵不休的态势……因为起名字的确是一项艺术,而在艺术上主观的成分更多一些,你看这样好,他看那样好……的确没有十全十美的方法,但……我们无论采用哪一种方法一定要前后统一啊。我推荐你读一下《Ottinger's Rules for Variable and Class Naming》这篇文章。”老C挠挠头,“另外在C领域也有一些很有名的标准,比如《MISRA C rules reference》,就是一个关于C语言很有名气的标准;而在C++领域,如果你没有看过《C++ Coding Standards 101 Rules Guidelines and Best Practices》这本书,最好不要说自己会C++,否则会遭到道上朋友们的BS。不过,不要盲目的跟随一项规则,没有好的规则,只有合适的规则,任何规则的应用都和环境有关,在某种环境下好的规则,在另外一种环境下就有可能变得很糟糕——因此,不要盲从规则,规则不能代替你自己的思考——我们需要了解某项规则应用的环境,理解为什么它是好的,尤其要注意例外的情况。总之不要做狂热的语言分子,不要错误的认为只有自己坚持的那一套才是最好的,要懂得心态开放,互相学习。”
“嗯,好像是这么回事。”小P若有所悟的说到。
“呵呵,有些看似违背了规范的做法也可以产生不错的结果,”老C补充道,“尤其当你毕业进入一家企业,如果那是一个有水准,有抱负,有责任的企业,一定会对你进行编码规范方面的培训的。虽然这些规范本身可能有这样、那样的不足,或者本身就违反了某些规范……但,只要大家都坚持,采用统一的方式去生产代码,这样往往会产生好的结果。产生了好结果的做法就是正确的做法,而往往一些不好的结果产生的原因不是我们做法错了,而是没有坚持……”
“是么?多么希望我们的课堂上可以讲讲类似的内容啊。”小P稍微有些遗憾,“那么你一般怎么写程序呢?”
“呵呵,我自己也有一套习惯,而且也在不断刷新……最主要的是保持一致——和你的团队,使用的库或者以后你的公司规定。”
“是啊,”小P点点头,“要不你先给我做个示范,以后我们教研室就使用这个规范如何?”
“呵呵,那多不好意思……”老C一边谦虚,一边在纸上写下如下内容,“一般用C++编码时,我习惯这样命名……”
#define LIKE_THIS
int likeThis;
void LikeThis ();
void LikeThis()
{
}
class LikeThis
{
public:
void likeThis();
private:
int field_;
}
enum LikeThis;
struct LikeThis;
typedef int INT16;
for (i = 0; i < 5; ++i)
{
}
......
“而使用C时,我习惯这样。”
typedef enum tagLIKE_THIS {} LIKE_THIS;
typedef struct tagLIKE_THIS {} LIKE_THIS;
“总之,利用大小写和空格区分出有用的信息,并坚持统一的做法,”老C说,“我再随便划拉几下,你看看有什么不同。”
代码片段1:
#define m1 50
#define m2 4
typedef enum cars{ yugo, ford, buick, pontiac } carmakes;
typedef struct one_carsale
{
carmakes CarMake;
char CustomerName[m1], CarMode[m1];
float Cost;
one_carsale* NextCarSalePtr;
}acar;
typedef struct salesperson{
char SalesPersonsName[m1];
float CommissionRate, BaseSalary, WeeklyPaycheck;
acar** NextNode;
}aperson;
acar* NexNodePtr[m2];
aperson Sale[m2];
代码片段2:
#define MAX_NAMELENGTH 50
#define MAX_SALESPEOPLE 4
/* makes of cars being sold. */
typedef enum tagCAR_MAKES { YUGO, FORD, BUICK, PONTIAC } CAR_MAKES;
/* structure to represent each car sale. */
typedef struct tagONE_CARSALE
{
CAR_MAKES carMake_;
char customerName_[MAX_NAMELENGTH];
char carModel_[MAX_NAMELENGTH];
float cost_;
ONE_CARSALE* nextCarSalePtr_;
}ONE_CARSALE;
/* structure to represent each individual sales person. */
typedef struct tagSALES_PERSON
{
char salesPersonsName_[MAX_NAMELENGTH];
float commissionRate_;
float baseSalary_;
float weeklyPaycheck_;
ONE_CARSALE** headerNode_;
}ONE_SALESPERSON;
/* declaration for non-standard array-of-pointers. */
ONE_CARSALE* g_headerNodePtr[MAX_SALESPEOPLE];
/* array of salespeople. */
ONE_SALESPERSON g_salesTeam[MAX_SALESPEOPLE];
“嗯,片段2的代码的确好理解一些,将一组链表的头指针放到一个数组中,而且从ONE_SALESPERSON类型的对象可以索引到 ONE_CARSALE对象的链表。基本上不用费什么功夫就可以理解,”小P挠挠头,“但是片段1的代码,虽然内容和片段2一样,但是……好像有些让然看不明白啊。”小P有些不好意思,“就像我写的一样……”
“呵呵,不要自责,没有关系的,这个是我们每个人必经的阶段……”老C安慰小P,“这些就是代码的品质,看看一个人写的代码,就知道他的思维和经验。让我们共同努力写出优雅的高品质的代码吧。”老C作激昂状。
“嗯,我一定好好看看你推荐的资料。”
“现在外表问题我们已经做过一些概要性的讨论了,反正周末无事,我们来教研室讨论一下程序的内在如何?”老C询问道。
“好吧,时间也不早了……”
“我请,我请……”老C一边说,一边摸着口袋和小P向门外走去。
(小心后面还有坑)