第一桶 从C到C++ 第五碗 陈老C谈编码规范 潘小P学江湖黑话

     “今天那个新加坡的叫兽讲的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向门外走去。



(小心后面还有坑)


 

posted on 2009-01-21 16:53 Anderson 阅读(1918) 评论(2)  编辑 收藏 引用

评论

# re: 第一桶 从C到C++ 第五碗 陈老C谈编码规范 潘小P学江湖黑话 2009-01-21 21:45 七星重剑

很好的c/c++教程啊,当年我学习的时候咋就没看到这样的好文章呢  回复  更多评论   

# re: 第一桶 从C到C++ 第五碗 陈老C谈编码规范 潘小P学江湖黑话 2009-01-23 23:43 imnobody

very good job,
thanks a lot  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2009年1月>
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

导航

统计

常用链接

留言簿(6)

随笔档案(21)

文章档案(1)

搜索

最新评论

阅读排行榜

评论排行榜