Linux內(nèi)核編碼風(fēng)格(編程代碼風(fēng)格推薦)_第1頁(yè)
Linux內(nèi)核編碼風(fēng)格(編程代碼風(fēng)格推薦)_第2頁(yè)
Linux內(nèi)核編碼風(fēng)格(編程代碼風(fēng)格推薦)_第3頁(yè)
Linux內(nèi)核編碼風(fēng)格(編程代碼風(fēng)格推薦)_第4頁(yè)
Linux內(nèi)核編碼風(fēng)格(編程代碼風(fēng)格推薦)_第5頁(yè)
已閱讀5頁(yè),還剩10頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、這是翻譯版本,英文原版是linux源碼Documentation文件夾下的CodingStyle一個(gè)良好風(fēng)格的程序看起來(lái)直觀、美觀,便于閱讀,還能有助于對(duì)程序的理解,特別在代碼量比較大情況下更顯現(xiàn)編碼素質(zhì)的重要性。相反沒(méi)有良好的風(fēng)格的代碼讀起來(lái)難看、晦澀,甚至有時(shí)候一個(gè)括號(hào)沒(méi)對(duì)齊就能造成對(duì)程序的曲解或者不理解。我曾經(jīng)就遇見(jiàn)過(guò)這樣的情況,花費(fèi)了很多不必要的時(shí)間在程序的上下文對(duì)照上,還debug了半天沒(méi)理解的程序。后來(lái)直接用indent-kr-i8給他轉(zhuǎn)換格式來(lái)看了。特此轉(zhuǎn)過(guò)來(lái)一個(gè)關(guān)于代碼風(fēng)格的帖子分享一下Linux 內(nèi)核編碼風(fēng)格這是一份簡(jiǎn)短的,描述linux內(nèi)核首選編碼風(fēng)格的文檔。編碼風(fēng)格是很個(gè)

2、人化的東西,而且我也不愿意把我的觀點(diǎn)強(qiáng)加給任何人,不過(guò)這里所講述的是我必須要維護(hù)的代碼所遵守的風(fēng)格,并且我也希望絕大多數(shù)其他代碼也能遵守這個(gè)風(fēng)格。所以請(qǐng)至少考慮一下本文所述的觀點(diǎn)首先,我建議你打印一份GNU的編碼規(guī)范,然后不要讀它。燒掉它,這是一個(gè)很高調(diào)的具有象征意義的姿態(tài)。Anyway,heregoes:第一章:縮進(jìn)制表符是8個(gè)字符,所以縮進(jìn)也是8個(gè)字符。有些異端運(yùn)動(dòng)試圖將縮進(jìn)變?yōu)?(乃至2)個(gè)字符深,這跟嘗試著將圓周率PI的值定義為3沒(méi)什么兩樣。理由:縮進(jìn)的全部意義就在于清楚的定義一個(gè)控制塊起止于何處。尤其是當(dāng)你盯著你的屏幕連續(xù)看了20小時(shí)之后,你將會(huì)發(fā)現(xiàn)大一點(diǎn)的縮進(jìn)將會(huì)使你更容易分辨縮進(jìn)

3、?,F(xiàn)在,有些人會(huì)抱怨8個(gè)字符的縮進(jìn)會(huì)使代碼向右邊移動(dòng)的太遠(yuǎn),在80個(gè)字符的終端屏幕上就很難讀這樣的代碼。這個(gè)問(wèn)題的答案是,如果你需要3級(jí)以上的縮進(jìn),不管縮進(jìn)深度如何你的代碼已經(jīng)有問(wèn)題了,應(yīng)該修正你的程序。簡(jiǎn)而言之,8個(gè)字符的縮進(jìn)可以讓代碼更容易閱讀,還有一個(gè)好處是當(dāng)你的函數(shù)嵌套太深的時(shí)候可以向你提出告警。請(qǐng)留意這個(gè)警告。在switch語(yǔ)句中消除多級(jí)縮進(jìn)的首選的方式是讓switch和從屬于它的caseB簽對(duì)齊于同一列,而不要兩次縮進(jìn)”“case簽。比如:switch(suffix)caseG:caseg:mem=30;break;caseM:casem:mem=20;break;caseK:ca

4、sek:memfor、while、do)。比如:switch(action)caseKOBJ_ADD:returnadd;caseKOBJ_REMOVE:returnremove;caseKOBJ_CHANGE:returnchange;default:returnNULL;)不過(guò),有一種特殊情況,命名函數(shù):它們的起始大括號(hào)放置于下一行的開(kāi)頭,這樣:intfunction(intx)bodyoffunction)全世界的異端可能會(huì)抱怨這個(gè)不一致性,呃確實(shí)是不一致的,不過(guò)所有思維健全的人都知道(a)K&R是正確的,并且(b)K&R是正確的。另外,不管怎樣函數(shù)都是特殊的(在C語(yǔ)言中

5、,函數(shù)是不能嵌套的)。注意結(jié)束大括號(hào)獨(dú)自占據(jù)一行,除非它后面跟著同一個(gè)語(yǔ)句的剩余部分,比如說(shuō)do語(yǔ)句中的while或者if語(yǔ)句中的“else,”像這樣:dobodyofdo-loopwhile(condition);if(x=y)elseif(xy)else理由:K&R。也請(qǐng)注意這種大括號(hào)的放置方式還能使空(或者差不多空的)行的數(shù)量最小化,同時(shí)不失可讀性。因此,由于你的屏幕上的新行的供應(yīng)不是可回收的資源(想想25行的終端屏幕),你將會(huì)有更多的空行來(lái)放置注釋。僅有一個(gè)單獨(dú)的語(yǔ)句時(shí),不用加不必要的大括號(hào)。和縮進(jìn)大小不同,選擇或棄用某種放置策Kernighan和Ritchie展示給我們的,,

6、所以:if(condition)action();這點(diǎn)不適用于本身為某個(gè)條件語(yǔ)句的一個(gè)分支的單獨(dú)語(yǔ)句。這時(shí)應(yīng)該兩個(gè)分支里都使用大括號(hào)。if(condition)do_this();do_that();elseotherwise();3.1:空格Linux內(nèi)核的空格使用方格(主要)取決于它是用于函數(shù)還是關(guān)鍵字。(大多數(shù))關(guān)鍵字后要加一個(gè)空格。值得注意的例外是sizeof、typeof、alignof和_attribute_,這些關(guān)鍵字在一定程度上看起來(lái)更像函數(shù)(它們?cè)贚inux里也常常伴隨小括號(hào)使用,盡管在C語(yǔ)言里這樣的小括號(hào)不是必需的,就像structfileinfoinfo聲明過(guò)后的size

7、ofinfo)”所以在這些關(guān)鍵字之后放一個(gè)空格:if,switch,case,for,do,while但是不在sizeof、typeof、alignof或者_(dá)attribute_這些關(guān)鍵字之后放空格。 例如,s=sizeof(structfile);不要在小括號(hào)里的表達(dá)式兩側(cè)加空格。這是一個(gè)反例:s=sizeof(structfile);當(dāng)聲明指針類型或者返回指針類型的函數(shù)時(shí),“*的首選使用方式是使之靠近變量名或者函數(shù)名,而不是靠近類型名。例子:char*linux_banner;unsignedlonglongmemparse(char*ptr,char*retptr);char*match

8、_strdup(substring_t*s);在大多數(shù)二元和三元操作符兩側(cè)使用一個(gè)空格,例如下面所有這些操作符:=+-*/%|&A=!=?:但是一元操作符后不要加空格:&*+!sizeoftypeofalignof_attribute_defined后綴自增和自減一元操作符前不加空格:+-前綴自增和自減一元操作符后不加空格:+-“和-”結(jié)構(gòu)體成員操作符前后不加空格。不要在行尾留空白。有些可以自動(dòng)縮進(jìn)的編輯器會(huì)在新行的行首加入適量的空白,然后你就可以直接在那一行輸入代碼。不過(guò)假如你最后沒(méi)有在那一行輸入代碼,有些編輯器就不會(huì)移除已經(jīng)加入的空白,就像你故意留下一個(gè)只有空白的行。包含行

9、尾空白的行就這樣產(chǎn)生了。當(dāng)Git發(fā)現(xiàn)補(bǔ)丁包含了行尾空白的時(shí)候會(huì)警告你,并且可以應(yīng)你的要求去掉行尾空白;不過(guò)如果你是正在打一系列補(bǔ)丁,這樣做會(huì)導(dǎo)致后面的補(bǔ)丁失敗,因?yàn)槟愀淖兞搜a(bǔ)丁的上下文。第四章:命名C是一個(gè)簡(jiǎn)樸的語(yǔ)言,你的命名也應(yīng)該這樣。和Modula-2和Pascal程序員不同,C程序員不使用類似ThisVariablelsATemporaryCounter這樣華麗的名字。C程序員會(huì)稱那個(gè)變量為“tmp,”這樣寫起來(lái)會(huì)更容易,而且至少不會(huì)令其難于理解。不過(guò),雖然混用大小寫的名字是不提倡使用的,但是全局變量還是需要一個(gè)具描述性的名字。稱一個(gè)全局函數(shù)為“foo是一個(gè)難以饒恕的錯(cuò)誤。全局變量(只有

10、當(dāng)你真正需要它們的時(shí)候再用它)需要有一個(gè)具描述性的名字,就像全局函數(shù)。如果你有一個(gè)可以計(jì)算活動(dòng)用戶數(shù)量的函數(shù),你應(yīng)該叫它c(diǎn)ount_a(tive_users()”或者類似的名字,你不應(yīng)該叫它c(diǎn)ntuser()?!痹诤瘮?shù)名中包含函數(shù)類型(所謂的匈牙利命名法)是腦子出了問(wèn)題一一編譯器知道那些類型而且能夠檢查那些類型,這樣做只能把程序員弄糊涂了。難怪微軟總是制造出有問(wèn)題的程序。本地變量名應(yīng)該簡(jiǎn)短, 而且能夠表達(dá)相關(guān)的含義。 如果你有一些隨機(jī)的整數(shù)型的循環(huán)計(jì)數(shù)器, 它應(yīng)該被稱為“i。 ”叫它loop_counter并無(wú)益處,如果它沒(méi)有可能被誤解的話。類似的“tmp”可以用來(lái)稱呼任意類型的臨時(shí)變量。如果

11、你怕混淆了你的本地變量名,你就遇到另一個(gè)問(wèn)題了,叫做函數(shù)增長(zhǎng)荷爾蒙失衡綜合癥。請(qǐng)看第六章(函數(shù))。第五章:Typedef不要使用類似“vps_t之類的東西。對(duì)結(jié)構(gòu)體和指針使用typedef是一個(gè)錯(cuò)誤。當(dāng)你在代碼里看到:vps_ta;這代表什么意思呢?相反,如果是這樣structvirtual_container*a;你就知道“娉什么了。很多人認(rèn)為typedef能提高可讀性實(shí)際不是這樣的。它們只在下列情況下有用:(a)完全不透明的對(duì)象(這種情況下要主動(dòng)使用typedef來(lái)隱藏這個(gè)對(duì)象實(shí)際上是什么)。例如:pte_tl?不透明對(duì)象,你只能用合適的訪問(wèn)函數(shù)來(lái)訪問(wèn)它們。注意!不透明性和訪問(wèn)函數(shù)本身”是

12、不好的。我們使用pte_t等類型的原因在于真的是完全沒(méi)有任何共用的可訪問(wèn)信息。(b)清楚的整數(shù)類型,這樣抽象層就可以幫助我們消除到底是int還是long的混淆。u8/u16/u32是完全沒(méi)有問(wèn)題的typedef,不過(guò)它們更符合(d)中所言,而不是這里。再次注意!要這樣做,必須事出有因。如果某個(gè)變量是aunsignedlong,那么沒(méi)有必要typedefunsignedlongmyflags_t;不過(guò)如果有一個(gè)明確的原因,比如它在某種情況下可能會(huì)是一個(gè)unsignedint而”在其他情況下可能為unsignedlong,那么就不要猶豫,請(qǐng)務(wù)必使用typedef。(c)當(dāng)你使用sparse按字面的

13、創(chuàng)建一個(gè)新類型來(lái)做類型檢查的時(shí)候(d)和標(biāo)準(zhǔn)C99類型相同的類型,在某些例外的情況下。雖然讓眼睛和腦筋來(lái)適應(yīng)新的標(biāo)準(zhǔn)類型比如“uint32_t不需要花很多時(shí)間,可以有些人仍然拒絕使用它們。因此,Linux特有的等同于標(biāo)準(zhǔn)類型的u8/u16/u32/u64類型和它們的有符號(hào)類型是被允許的一一盡管在你自己的新代碼中,它們不是強(qiáng)制要求要使用的。當(dāng)編輯已經(jīng)使用了某個(gè)類型集的已有代碼時(shí),你應(yīng)該遵循那些代碼中已經(jīng)做出的選擇。(e)可以在用戶空間安全使用的類型。在某些用戶空間可見(jiàn)的結(jié)構(gòu)體里,我們不能要求C99類型而且不能用上面提到的“u32”類型。因此,我們?cè)谂c用戶空間共享的所有結(jié)構(gòu)體中使用_u32和類似的

14、類型??赡苓€有其他的情況,不過(guò)基本的規(guī)則是永遠(yuǎn)不要使用typedef,除非你可以明確的應(yīng)用上述某個(gè)規(guī)則中的一個(gè)??偟膩?lái)說(shuō),如果一個(gè)指針或者一個(gè)結(jié)構(gòu)體里的元素可以合理的被直接訪問(wèn)到,那么它們就不應(yīng)該是一個(gè)typedef。第六章:函數(shù)函數(shù)應(yīng)該簡(jiǎn)短而漂亮,并且只完成一件事情。函數(shù)應(yīng)該可以一屏或者兩屏顯示完(我們都知道ISO/ANSI屏幕大小是80 x24),只做一件事情,而且把它做好。一個(gè)函數(shù)的最大長(zhǎng)度是和該函數(shù)的復(fù)雜度和縮進(jìn)級(jí)數(shù)成反比的。所以,如果你有一個(gè)理論上很簡(jiǎn)單的只有一個(gè)很長(zhǎng)(但是簡(jiǎn)單)的case語(yǔ)句的函數(shù),而且你需要在每個(gè)case里做很多很小的事情,這樣的函數(shù)盡管很長(zhǎng),但也是可以的。不過(guò),

15、如果你有一個(gè)復(fù)雜的函數(shù),而且你懷疑一個(gè)天分不是很高的高中一年級(jí)學(xué)生可能甚至搞不清楚這個(gè)函數(shù)的目的,你應(yīng)該更嚴(yán)格的遵守最大限制。使用輔助函數(shù),并為之取個(gè)具描述性的名字(如果你覺(jué)得其對(duì)性能要求嚴(yán)格的話,你可以要求編譯器將它們內(nèi)聯(lián)展開(kāi),它往往會(huì)比你更好的完成任務(wù)。)函數(shù)的另外一個(gè)衡量標(biāo)準(zhǔn)是本地變量的數(shù)量。此數(shù)量不應(yīng)超過(guò)5-10個(gè),否則你的函數(shù)就有問(wèn)題了。重新考慮一下你的函數(shù),把它分拆成更小的函數(shù)。人的大腦一般可以輕松的同時(shí)跟蹤7個(gè)不同的事物,如果再增多的話,就會(huì)糊涂了。即便你聰穎過(guò)人,你也可能會(huì)記不清你2個(gè)星期前做過(guò)的事情。在源文件里,使用空行隔開(kāi)不同的函數(shù)。如果該函數(shù)需要被導(dǎo)出,它的EXPORT*

16、宏應(yīng)該緊貼在它的結(jié)束大括號(hào)之下。比如:intsystem_is_up(void)(returnsystem_state=SYSTEM_RUNNING;EXPORT_SYMBOL(system_is_up);在函數(shù)原型中,包含函數(shù)名和它們的數(shù)據(jù)類型。雖然C語(yǔ)言里沒(méi)有這樣的要求,在Linux里這是提倡的做法,因?yàn)檫@樣可以很簡(jiǎn)單的給讀者提供更多的有價(jià)值的信息。第七章:集中的函數(shù)退由途徑雖然被某些人聲稱已經(jīng)過(guò)時(shí),但是goto語(yǔ)句的等價(jià)物還是經(jīng)常被編譯器所使用,具體形式是無(wú)條件跳轉(zhuǎn)指令。當(dāng)一個(gè)函數(shù)從多個(gè)位置退出并且需要做一些通用的清潔工作的時(shí)候,goto的好處就顯現(xiàn)出來(lái)了。理由是:- 無(wú)條件語(yǔ)句容易理解

17、和跟蹤- 嵌套程度減小- 可以避免由于修改時(shí)忘記更新某個(gè)單獨(dú)的退出點(diǎn)而導(dǎo)致的錯(cuò)誤- 減輕了編譯器的工作,無(wú)需刪除冗余代碼;)intfun(inta)(intresult=0;char*buffer=kmalloc(SIZE);if(buffer=NULL)return-ENOMEM;if(condition1)while(loop1)result=1;gotoout;out:kfree(buffer);returnresult;第八章:注釋注釋是好的,不過(guò)有過(guò)度注釋的危險(xiǎn)。永遠(yuǎn)不要在注釋里解釋你的代碼是如何運(yùn)作的:更好的做法是讓別人一看你的代碼就可以明白,解釋寫的很差的代碼是浪費(fèi)時(shí)間。一般的,

18、你想要你的注釋告訴別人你的代碼做了什么,而不是怎么做的。也請(qǐng)你不要把注釋放在一個(gè)函數(shù)體內(nèi)部:如果函數(shù)復(fù)雜到你需要獨(dú)立的注釋其中的一部分,你很可能需要回到第六章看一看。你可以做一些小注釋來(lái)注明或警告某些很聰明(或者槽糕)的做法,但不要加太多。你應(yīng)該做的,是把注釋放在函數(shù)的頭部,告訴人們它做了什么,也可以加上它做這些事情的原因。當(dāng)注釋內(nèi)核API函數(shù)時(shí),請(qǐng)使用kernel-doc格式。請(qǐng)看Documentation/kernel-doc-nano-HOWTO.txt和scripts/kernel-doc以獲得詳細(xì)信息。Linux的注釋風(fēng)格是C89/*.*/風(fēng)格不要使用C99風(fēng)格“.注釋長(zhǎng)(多行)的首

19、選注釋風(fēng)格是:/* Thisisthepreferredstyleformulti-line* commentsintheLinuxkernelsourcecode.* Pleaseuseitconsistently.* Description:Acolumnofasterisksontheleftside,*withbeginningandendingalmost-blanklines.* /注釋數(shù)據(jù)也是很重要的,不管是基本類型還是衍生類型。為了方便實(shí)現(xiàn)這一點(diǎn),每一行應(yīng)只聲明一個(gè)數(shù)據(jù)(不要使用逗號(hào)來(lái)一次聲明多個(gè)數(shù)據(jù))。這樣你就有空間來(lái)為每個(gè)數(shù)據(jù)寫一段小注釋來(lái)解釋它們的用途了。第九章:你已經(jīng)把

20、事情弄糟了這沒(méi)什么,我們都是這樣??赡苣愕氖褂昧撕荛L(zhǎng)時(shí)間Unix的朋友已經(jīng)告訴你“GNUemacs能自動(dòng)幫你格式化C源代碼,而且你也注意到了,確實(shí)是這樣,不過(guò)它所使用的默認(rèn)值和我們想要的相去甚遠(yuǎn)(實(shí)際上,甚至比隨機(jī)打的還要差一一無(wú)數(shù)個(gè)猴子在GNUemacs里打字永遠(yuǎn)不會(huì)創(chuàng)造出一個(gè)好程序)(譯注:請(qǐng)參考InfiniteMonkeyTheorem)所以你要么放棄GNUemacs,要么改變它讓它使用更合理的設(shè)定。要采用后一個(gè)方案,你可以把下面這段粘貼到你的.emacs文件里。(defunlinux-c-mode()CmodewithadjusteddefaultsforusewiththeLinux

21、kernel.(interactive)(c-mode)(c-set-styleK&R)(setqtab-width8)(setqindent-tabs-modet)(setqc-basic-offset8)這樣就定義了M-xlinux-c-mode命令。當(dāng)你hack一個(gè)模塊的時(shí)候,如果你把字符串-*-linux-c-*-放在頭兩行的某個(gè)位置,這個(gè)模式將會(huì)被自動(dòng)調(diào)用。如果你希望在你修改/usr/src/linux里的文件時(shí)魔術(shù)般自動(dòng)打開(kāi)linux-c-mode的話,你也可能需要添力口(setqauto-mode-alist(cons(/usr/src/linux.*/.*.ch$”.l

22、inux-c-mode)auto-mode-alist)到你的.emacs文件里。不過(guò)就算你嘗試讓emacs正確的格式化代碼失敗了,也并不意味著你失去了一切:還可以用不過(guò),GNUindent也有和GNUemacs一樣有問(wèn)題的設(shè)定,所以你需要給它一些命令選項(xiàng)。不過(guò),這還不算太糟糕,因?yàn)榫退闶荊NUindent的作者也認(rèn)同K&R的權(quán)威性(GNU的人并不是壞人,他們只是在這個(gè)問(wèn)題上被嚴(yán)重的誤導(dǎo)了),所以你只要給indent指定選項(xiàng)-kr-i8”(代表“K&R8個(gè)字符縮進(jìn)”),或者使用“scripts/Lindent,這樣就可以以最時(shí)髦的方式縮進(jìn)源代碼。indent有很多選項(xiàng),特別是重

23、新格式化注釋的時(shí)候,你可能需要看一下它的手冊(cè)頁(yè)。不過(guò)記?。骸癷ndent不能修正壞的編程習(xí)慣。第十章:Kconfig 配置文件對(duì)于遍布源碼樹(shù)的所有Kcon的*配置文件來(lái)說(shuō),它們縮進(jìn)方式與C代碼相比有所不同。緊挨在“config定義下面的行縮進(jìn)一個(gè)制表符,幫助信息則再多縮進(jìn)2個(gè)空格。比如:configAUDITboolAuditingsupportdependsonNEThelpEnableauditinginfrastructurethatcanbeusedwithanotherkernelsubsystem,suchasSELinux(whichrequiresthisforloggingo

24、favcmessagesoutput).Doesnotdosystem-callauditingwithoutCONFIG_AUDITSYSCALL.仍然被認(rèn)為不夠穩(wěn)定的功能應(yīng)該被定義為依賴于“EXPERIMENTAL:configSLUBdependsonEXPERIMENTAL&!ARCH_USES_SLAB_PAGE_STRUCTboolSLUB(UnqueuedAllocator).而那些危險(xiǎn)的功能(比如某些文件系統(tǒng)的寫支持)應(yīng)該在它們的提示字符串里顯著的聲明這一點(diǎn):configADFS_FS_RWboolADFSwritesupport(DANGEROUS)dependson

25、ADFS_FS.要查看配置文件的完整文檔,請(qǐng)看Documentation/kbuild/kcon巾g-language.txt。第十一章:數(shù)據(jù)結(jié)構(gòu)如果一個(gè)數(shù)據(jù)結(jié)構(gòu),在創(chuàng)建和銷毀它的單線執(zhí)行環(huán)境之外可見(jiàn),那么它必須要有一個(gè)引用計(jì)數(shù)器。內(nèi)核里沒(méi)有垃圾收集(并且內(nèi)核之外的垃圾收集慢且效率低下),這意味著你絕對(duì)需要記錄你對(duì)這種數(shù)據(jù)結(jié)構(gòu)的使用情況。引用計(jì)數(shù)意味著你能夠避免上鎖,并且允許多個(gè)用戶并行訪問(wèn)這個(gè)數(shù)據(jù)結(jié)構(gòu)一一而不需要擔(dān)心這個(gè)數(shù)據(jù)結(jié)構(gòu)僅僅因?yàn)闀簳r(shí)不被使用就消失了,那些用戶可能不過(guò)是沉睡了一陣或者做了一些其他事情而已。注意上鎖不能取代引用計(jì)數(shù)。上鎖是為了保持?jǐn)?shù)據(jù)結(jié)構(gòu)的一致性,而引用計(jì)數(shù)是一個(gè)內(nèi)存管理

26、技巧。通常二者都需要,不要把兩個(gè)搞混了。很多數(shù)據(jù)結(jié)構(gòu)實(shí)際上有2級(jí)引用計(jì)數(shù),它們通常有不同類”的用戶。子類計(jì)數(shù)器統(tǒng)計(jì)子類用戶的數(shù)量,每當(dāng)子類計(jì)數(shù)器減至零時(shí),全局計(jì)數(shù)器減一。這種多級(jí)引用計(jì)數(shù)”的例子可以在內(nèi)存管理(structmm_struct:mm_users和mm_count)和文件系統(tǒng)(“structsuper_block:s_count和s_active)中找至U。記住:如果另一個(gè)執(zhí)行線索可以找到你的數(shù)據(jù)結(jié)構(gòu),但是這個(gè)數(shù)據(jù)結(jié)構(gòu)沒(méi)有引用計(jì)數(shù)器,這里幾乎肯定是一個(gè)bug。第十二章:宏,列舉(enum)和 RTL定義常量和列舉里的標(biāo)簽的宏的名字需要大寫。#defineCONSTANT0 x123

27、45在定義幾個(gè)相關(guān)的常量時(shí),最好用列舉。宏的名字請(qǐng)用大寫字母,不過(guò)形如函數(shù)的宏的名字可以用小寫字母。一般的,如果能寫成內(nèi)聯(lián)函數(shù)就不要寫成像函數(shù)的宏。含有多個(gè)語(yǔ)句的宏應(yīng)該被包含在一個(gè)#definemacrofun(a,b,c)doif(a=5)do_this(b,c);while(0)使用宏的時(shí)候應(yīng)避免的事情:1)影響控制流程的宏:#defineFOO(x)doif(blah(x)0)return-EBUGGERED;while(0)非常不好。它看起來(lái)像一個(gè)函數(shù),不過(guò)卻能導(dǎo)致dontbreaktheinternalparsersofthosewhowillreadthecode.2)依賴于一個(gè)固

28、定名字的本地變量的宏:#defineFOO(val)bar(index,val)可能看起來(lái)像是個(gè)不錯(cuò)的東西,不過(guò)它非常容易把讀代碼的人搞糊涂,而且容易導(dǎo)致看起來(lái)不相關(guān)的改動(dòng)帶來(lái)錯(cuò)誤。3)作為左值的帶參數(shù)的宏:FOO(x)=y;如果有人把FOO變成一個(gè)內(nèi)聯(lián)函數(shù)的話,這種用法就會(huì)出錯(cuò)了。do-while代碼塊里:調(diào)用”它的函數(shù)退出;4)忘記了優(yōu)先級(jí):使用表達(dá)式定義常量的宏必須將表達(dá)式置于一對(duì)小括號(hào)之內(nèi)。帶參數(shù)的宏也要注意此類問(wèn)題。#defineCONSTANT0 x4000#defineCONSTEXP(CONSTANT|3)cpp手冊(cè)對(duì)宏的講解很詳細(xì)。Gccinternals手冊(cè)也詳細(xì)講解了RT

29、L(譯注:registertransferlanguage),內(nèi)核里的匯編語(yǔ)言經(jīng)常用到它。第十三章:打印內(nèi)核消息內(nèi)核開(kāi)發(fā)者應(yīng)該是受過(guò)良好教育的。請(qǐng)一定注意內(nèi)核信息的拼寫,以給人以好的印象。不要用不規(guī)范的單詞比如“dont,而要用donot或者dont?!北WC這些信息簡(jiǎn)單、明了、無(wú)歧義。內(nèi)核信息不必以句點(diǎn)結(jié)束。在小括號(hào)里打印數(shù)字(d)沒(méi)有任何價(jià)值,應(yīng)該避免這樣做。里有一些驅(qū)動(dòng)模型診斷宏,你應(yīng)該使用它們,以確保信息對(duì)應(yīng)于正確的設(shè)備和驅(qū)動(dòng),并且被標(biāo)記了正確的消息級(jí)別。這些宏有:dev_err(),dev_warn(),dev_info()等等。對(duì)于那些不和某個(gè)特定設(shè)備相關(guān)連的信息,定義了pr_deb

30、ug()和pr_info()。寫出好的調(diào)試信息可以是一個(gè)很大的挑戰(zhàn);當(dāng)你寫出來(lái)之后,這些信息在遠(yuǎn)程除錯(cuò)的時(shí)候就會(huì)成為極大的幫助。當(dāng)DEBUG符號(hào)沒(méi)有被定義的時(shí)候,這些信息不應(yīng)該被編譯進(jìn)內(nèi)核里(也就是說(shuō),默認(rèn)地,它們不應(yīng)該被包含在內(nèi))。如果你使用dev_dbg()或者pr_debug(),就能自動(dòng)達(dá)到這個(gè)效果。很多子系統(tǒng)擁有Kconfig選項(xiàng)來(lái)啟用-DDEBUG。還有一個(gè)相關(guān)的慣例是使用VERBOSE_DEBUG來(lái)添加dev_vdbg()消息到那些已經(jīng)由DEBUG啟用的消息之上。第十四章:分配內(nèi)存內(nèi)核提供了下面的一般用途的內(nèi)存分配函數(shù):kmalloc(),kzalloc(),kcalloc()和

31、vmalloc()。請(qǐng)參考API文檔以獲取有關(guān)它們的詳細(xì)信息。傳遞結(jié)構(gòu)體大小的首選形式是這樣的:p=kmalloc(sizeof(*p),.);另外一種傳遞方式中,sizeof的操作數(shù)是結(jié)構(gòu)體的名字,這樣會(huì)降低可讀性,并且可能會(huì)引入bug。有可能指針變量類型被改變時(shí),而對(duì)應(yīng)的傳遞給內(nèi)存分配函數(shù)的sizeof的結(jié)果不變。強(qiáng)制轉(zhuǎn)換一個(gè)void指針?lè)祷刂凳嵌嘤嗟?。C語(yǔ)言本身保證了從void指針到其他任何指針類型的轉(zhuǎn)換是沒(méi)有問(wèn)題的。第十五章:內(nèi)聯(lián)弊病有一個(gè)常見(jiàn)的誤解是內(nèi)聯(lián)函數(shù)是gcc提供的可以讓代碼運(yùn)行更快的一個(gè)選項(xiàng)。雖然使用內(nèi)聯(lián)函數(shù)有時(shí)候是恰當(dāng)?shù)模ū热缱鳛橐环N替代宏的方式,請(qǐng)看第十二章),不過(guò)很多情

32、況下不是這樣。inline關(guān)鍵字的過(guò)度使用會(huì)使內(nèi)核變大,從而使整個(gè)系統(tǒng)運(yùn)行速度變慢。因?yàn)榇髢?nèi)核會(huì)占用更多的指令高速緩存(譯注:一級(jí)緩存通常是指令緩存和數(shù)據(jù)緩存分開(kāi)的)而且會(huì)導(dǎo)致pagecache的可用內(nèi)存減少。想象一下,一次pagecache未命中就會(huì)導(dǎo)致一次磁盤尋址,將耗時(shí)5毫秒。5毫秒的時(shí)間內(nèi)CPU能執(zhí)行很多很多指令。一個(gè)基本的原則是如果一個(gè)函數(shù)有3行以上,就不要把它變成內(nèi)聯(lián)函數(shù)。這個(gè)原則的一個(gè)例外是,如果你知道某個(gè)參數(shù)是一個(gè)編譯時(shí)常量,而且因?yàn)檫@個(gè)常量你確定編譯器在編譯時(shí)能優(yōu)化掉你的函數(shù)的大部分代碼,那仍然可以給它加上inline關(guān)鍵字。kmalloc()內(nèi)聯(lián)函數(shù)就是一個(gè)很好的例子。人們經(jīng)常主張給static的而且只用了一次的函數(shù)加上inline,不會(huì)有任何損失,因?yàn)檫@種情況下沒(méi)有什么好權(quán)衡的。雖然從技術(shù)上說(shuō),這是正確的,不過(guò)gcc可以在沒(méi)有提示的情況下自動(dòng)使其內(nèi)聯(lián),而且其他用戶可能會(huì)要求移除inline,此種維護(hù)上的爭(zhēng)論會(huì)抵消可以告訴gcc來(lái)做某些事情的提示帶來(lái)的潛在價(jià)值。不管有沒(méi)有inline,這種函數(shù)都會(huì)被內(nèi)聯(lián)。第十六章:函數(shù)返回值及命名函數(shù)可以返回很多種不同類型的值,最常見(jiàn)的一種是表明函數(shù)執(zhí)行成功或者失敗的

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論