當前位置: 華文問答 > 數位

Linux 內核的 C 程式碼風格是怎樣的?

2015-04-17數位

關於Linux內核的程式碼風格,Linus Torvalds在很多年前就給出過「標準」,後來這個「標準」經過很多改進形成了現在的文件,保存在Linux內核源碼的Documentation/process/coding- style.rst檔裏:

註意我上面雖然用了「標準」兩個字,但這並不是一個通用標準,這個標準或者說守則僅限於Linux內核這個計畫。每個計畫或者說每個大型計畫都會有不止一個人在開發和維護,所以管理者為了維護程式碼的可讀性,往往會定義一種計畫範圍內的成文或不成文的程式碼風格讓送出程式碼的人遵守。

當然並不是所有的計畫都這樣嚴格,Linux算是對程式碼風格規定的比較成文的一個,以至於很多人在Linux內核計畫外也習慣性沿用這種風格。當然如果你要給一個已有的計畫貢獻程式碼,最好尊重那個計畫自己的編碼習慣。如果計畫裏沒有明確說明,可以透過觀察相關程式碼的樣子來判斷。

任何的程式語言都有很多的編程風格,網上一直爭吵不斷的就有很多,比如:

  1. 用Tab縮排還是空格縮排好
  2. 縮排2個格還是4個格還是8個格的距離好
  3. 花括弧是對齊還是不對齊
  4. 變量定義用大寫還是底線

……等等……

其實我想說這種蘿蔔白菜各有所愛的東西根本沒有爭論的必要,為這種事情爭執只能說明閑得dan疼。但是對於一個具體計畫而言,規定一個盡量統一的風格去遵守卻是很有意義的。我就見過一些多人維護的計畫裏,一個程式檔由於不同人送出的不同patch被改的「面目全非」,雖然沒有語法錯誤,但是讓人看著就很煩躁。你再給它提patch的時候,只能盡量做到一個檔裏前後是2格對齊的時候你也用2格,前後是8格對齊的時候你也用8格,上面是4格下面是8格對齊你要在中間加一行的時候就拋硬幣吧。有人可能會說,你給它都改了統一一下格式不就得了?不,如果你一次性調整很多格式,那就是另一個patch了,大量的無關修改會嚴重影響你當前patch的意義,一個patch一般就做一件特定的事,如果你要大量調整格式最好用另外單獨的patch,但是單純調整格式的patch會讓人覺得很……所以一般都是計畫的維護者自己看不下去了統一調整一下格式,或維護者表示願意讓你幫忙調整一下格式(少見)。扯遠了,言歸正傳,為了避免日後出現「面目全非」的程式碼格式,在統一要求和日常稽核的時候最好有統一的「標準」,用什麽作為標準並不十分重要(這一般由計畫核心團隊的審美觀價值觀來決定,其它參與者遵守就行),一個計畫有一個統一標準比較重要。

而Linux內核的程式碼風格就有一個成文的規定,就是我一開始說的那個文件。而且看過我這篇回答的人:

應該也了解到Linux對於patch也是也一定的格式要求,而為了方便patch中程式碼格式的稽核,還特意寫了一個自動檢查的程式在scripts目錄下叫checkpatch.pl:

$ ./scripts/checkpatch.pl 0001-xfs-remove-the-XFS_IOC_FSSETDM-definitions.patch total: 0 errors, 0 warnings, 55 lines checked 0001-xfs-remove-the-XFS_IOC_FSSETDM-definitions.patch has no obvious style problems and is ready for submission.

它可以幫你先自己檢查一下自己當前的patch格式是否符合Linux計畫的統一要求。當然我們不得不說這個檢查並不是那麽絕對,即使有錯誤報出來也要人工看一下具體情況是否需要修改,這並不是一個嚴格的必須過審的步驟,目前更多的是一個輔助,特別是對新人來說,可以節省別人給你調整格式問題的麻煩。

關於Linux中C語言的格式的描述有很多,比如縮排格式,花括弧格式,函式參數格式,變量和函式的定義要求等,舉一些簡單的例子,比如大家最關心的縮排,Linux內核要求統一使用Tab的8格寬度(當然顯示出來是不是8格也要看你本地編輯器對Tab的定義),像這樣(註意這裏的點只是想表示一個格的寬度,並不是要在這點點):

int main() { ........if (a == 1) ................return 0; }

還有比如花括弧的使用格式上,函式和非函式使用花括弧不一樣。函式的花括弧獨自占一行的行首對齊,像這樣:

void func(int a) { .... } int main() { .... }

而非函式的花括弧是不對齊的,像這樣:

if (a == 1) { ... } else if (b == 0) { ... } else { ... } while (x == y) { ... } switch (action) { case KOBJ_ADD: return "add"; case KOBJ_REMOVE: return "remove"; default: return NULL; }

這些是比較顯而易見的地方,當然除此之外還有很多要求,具體的我就不一一列舉了,請自行檢視上面的文件,以及參考已有的計畫內的成熟程式碼。在那個文件裏還「貼心」的給出了一個用於emacs的配置,可以幫助emacs使用者配置好自己用於Linux內核程式碼風格的縮排等格式,我目前也是使用了這個。

最後還是特別聲明,以上格式僅針對Linux內核計畫,且並沒有絕對的普適的優越性,所以沒必要拿著到別處去要求別人都認同你的審美。當然如果你喜歡可以將其作為自己的預設風格。