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