“今天那個新加坡的叫獸講的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向門外走去。
(小心后面還有坑)