2012軟考軟件設計師輔導:C/C++作用域引申出的編碼規(guī)范

字號:

編碼規(guī)范非常重要,不僅僅在于沒有了它在團體合作中互相讀不懂對方的代碼,還在于以后的自己也可能需要維護以前自己寫的代碼,還在于可讀性越強越不輕易犯一些常規(guī)錯誤。
    規(guī)范本身應該是一個規(guī)定,但C/C++在編碼上并沒有這樣的規(guī)定,凡符合C/C++語法的就是合格的代碼,但符合C/C++語法的代碼不一定是優(yōu)秀的代碼,要對一些不良行為做約定,比如不應該將局部使用的變量作為全局變量,這是其一;其二,代碼本身也可能會進行合作開發(fā)或后期維護,那么一個表達統(tǒng)一結構清楚的代碼是必要的。由這兩點產(chǎn)生了編碼規(guī)范,所以編碼規(guī)范就是公司或團體對代碼編寫的一個規(guī)定和約定。
    對于第二點而言,雖然其存在的價值是必須的,但是適用場合都有所不同性,且眾口難調,缺乏非此不可的科學依據(jù)。比如大家熟悉的匈牙利命名法,其在變量名稱中包含了類型信息,其優(yōu)點不言而喻,在代碼實現(xiàn)過程中非常方便,但缺點也有不少,比如變量本身就具有類型,而名稱中再次包含了類型信息,這是嚴重的冗余,修改變量類型就必須修改變量名稱,更主要的是沒有辦法保證它們的一致性,總之名稱應該是對功能的描述,而不應該含有類型信息。所以即使強如匈牙利命名法,在M$的編碼規(guī)范中也不將再存在。因為第二點不能放之四海而皆準,所以我將在這篇短文中講述第一點,有科學依據(jù)則易于為人接受,但我還是要強調一下,這第一點只是編碼規(guī)范存在理由的一部分,而不是全部,第二個理由也非常重要,其引申出來的規(guī)范不可缺少。
    要想寫出優(yōu)秀的C/C++代碼有很多注重點,不是一個小短文可以描述清楚的,我這里僅僅講述變量的作用域和生存期,根據(jù)這些規(guī)則產(chǎn)生的編碼規(guī)范會和你曾經(jīng)見到過的一些編碼規(guī)范有所抵觸,這不足為奇,比如很多編碼規(guī)范規(guī)定了函數(shù)體的行數(shù),過多的行數(shù)大部分情況下是因為功能結構化分不清,不利于閱讀,但卻不一定如此,假如在這個規(guī)定和規(guī)定這個規(guī)定的目的之間產(chǎn)生了抵觸,那么這時就應該舍棄這個規(guī)定,所以我認為稱它編碼建議勝于稱它編碼規(guī)范。
    對于編碼規(guī)范含義的講解至此結束,話入正題,對于一個面向過程的語言而言,函數(shù)過程是其基本單位,函數(shù)是一個功能完整的實現(xiàn)過程,面向對象也如此,只是類代替了函數(shù)過程的部分地位。
    為什么要將一個過程獨立成一個函數(shù)?這是因為此過程功能完整明確,在獨立成一個函數(shù)之后其還具備了復用的能力。
    為什么不將一個過程獨立成一個函數(shù)?這是因為此過程與其他部分耦合度太高,沒有明確的功能含義,即使獨立出來,也不存在可復用的場合。
    作用域就是起作用的范圍,一個應該在多處起作用的對象,不應該局限于一個小空間中,反之亦然。這里可以使用的有 函數(shù)、對象、名字空間 等,假如以上皆不符合,那么就應該使用為部分人所忽視的“{}”。
    以下就是一個對變量/過程的作用域和生存期的演示:
    在很多地方都可能會用到的函數(shù)或類型()
     {
     };
    一個功能函數(shù)或類型()
     {
    僅在此函數(shù)或類型中用到且多次用到的子函數(shù)或子類型() // C++沒有子函數(shù)這一說法,可以使用函數(shù)對象(仿函數(shù))替代
     {
     };
    在接下來的部分也需要用到的變量; // 注重這個分號
     {
    僅在這個{}中用到的臨時變量;
    僅在此函數(shù)或類型中用到且只用到一次的功能段
     }
    函數(shù)或類型其他部分;
     };
    這樣就將變量和過程局限在它們應有的空間中,避免了變量和過程對以后的變量和過程的污染,尤其在代碼量很大的程序中,而且因為有了{}區(qū)分不同的功能代碼,使得程序可讀性增強。當然一切還是了可讀性,看以下這個情況:
    某個功能代碼的第一行;
    某個功能代碼的第二行;
    某個功能代碼的第三行;
     {
    只為此功能實現(xiàn)一次的,由與此功能無邏輯關系的代碼第一行;
    第二行;
     …… ;
    第 n行;
     }
    某個功能代碼的第四行;
    某個功能代碼的第五行;
    某個功能代碼的第六行;
    這樣實現(xiàn)也許邏輯清楚,但在代碼編輯器中需要非常麻煩的上下翻頁才能看到連續(xù)的功能代碼,而且{}中的代碼太長,像個丑陋的補丁,這時候將{}中的代碼移到一個獨立子函數(shù)中比較適合,就變成了
    某個功能代碼的第三行;
     {
     call子函數(shù)( 參數(shù)s ); // 上下的{}可以不要
     }
    某個功能代碼的第四行;
    當然前面也提到過假如這個子函數(shù)和這個功能代碼段的耦合性太強的話,就需要傳遞很多的參數(shù),這沒有什么好的方法,因為這究竟是為了可讀性而作出的妥協(xié)。
    局部類(比如定義在函數(shù)內部的類)有一些令人不快的功能限制,比如沒辦法作為模板參數(shù),我還不知道在c++中為什么有這樣的限制,但這一點確實確實令人不快。