Linux Kernel Coding Style - 適合學C的初學者學習.老手參考
file: /usr/src/linux/Documentation/CodingStyle
Initial translation, 9/28 1997, by
syc@cc.ntu.edu.tw 蕭永慶
------------------------------------------------------------------
Linux kernel 程式設計規範
這是一篇描述linux kernel所期望的程式設計風格的短文. 程式風格是
因人而異的, 所以我不願意_強迫_他人接受我的看法, 但是現在我們是討
論一份我必須維護的程式碼,而我也偏好在其它方面使用這種風格.請你至少
考慮這裡所作的論點.
首先, 我想建議你印一份GNU程式設計風格指南出來, 然後千萬不要讀它.
把它燒掉, 它實在是一篇充滿代號的咒文.
總而言之, 這就是我要的這樣子:
第一章: 縮格
Tab就是八個空白, 所以縮格也就是八格. 有個邪說想把縮格
設成4(甚至2)格, 這就像是嚐試把PI的值定義成3一樣.
按: 縮格背後的真正意義是用來清楚的界定一個控制區塊的開始與結束.
特別是當你已經盯了連續20小時的螢幕的時候, 你就會發現使用大縮格
是如何有效的發揮它應有的功能.
到此為止,有些人會宣稱縮8格會讓程式碼移到太右邊去, 使得在80個字寬的
終端機螢幕下非常的難以閱讀. 我的回答是如果你需要多過3層的縮格,
無論如何你大概已經搞砸了, 應該要修改你的程式才對.
簡端的說,八格的縮格較容易閱讀, 並且,當你的副程式巢狀太深的話,
有個附加的預警效果. 要注意這個警告!
第二章: 括號的擺法
C設計風格中另外常被討論的就是括號的位置. 不像縮格的案例, 選擇括號的
擺設沒什麼特別的技術上的理由, 但是我較篇好的方式, 就像先賢Kernighan
和Ritchie所示範給我們看的樣子, 是把左大括號放在行尾, 然後右大括號
放在一行的最前面, 就是這樣子:
if (x 為 真) {
執行步驟 y
}
不過, 有一個例外, 就是函式: 函式的左大括號放在次一行的開頭, 如下:
int function(int x)
{
函式的內容
}
全世界的邪教徒會宣稱這個例外是...反正就是...不一致,但是所有思想正確
的人都知道及
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
按: K&R.
此外, 注意這種擺法使得在不失去可讀性下, 空白行(或者幾乎空白的行)的
數量最少. 因此, 當螢幕的行數有限的時候(這裡請考慮25行的螢幕), 你有
較多的空行可以放註解.
第三章: 命名
C是一個非常簡潔的語言, 所以你的命名也要一樣. 不像Modula-2和Pascal
的程式設計者, C程式設計者不會用像ThisVariableIsATemporaryCounter
這樣滑稽的名字. 一個C程式設計者會叫這個變數"tmp", 不僅較容易寫,
並且至少不會比較難以理解.
不過, 雖然不贊成使用混雜大小寫的名字, 但是全域變數一定須要具有
描述性的名字. 叫一個全域函式 "foo" 是一種故意犯錯的行為.
全域變數 (僅在必要的時後才使用之)須要有描述性的名字, 就像全域函式一樣.
如果你有一個函式用來數活躍的(active)使用者,你應該稱之為
"count_active_users()" 或者類似的名字, 不應該稱為 "cntusr()"
把函式的型別編進名字裡面(所謂的匈牙利表示法, Hungarian notation)是
頭殼壞去的行為 - 無論如何編譯器永遠知道這些形別,而且可以幫你檢查,
這種編碼只有令程式設計者更加搞不清楚而已. 難怪MicroSoft製造的
程式都有很多bug.
區域變數名字應該要簡短,並且恰到好處. 如果你有一些隨意的整數迴圈計數器
(loop counter), 它應該稱之為 "i". 如果沒有被混用的困擾的話, 叫它
"loop_counter" 是沒有效率的, 同樣的, "tmp" 可以是任何的型別的變數,
只要是這個變數用來儲存一些暫時的資料.
如果你怕搞混了你的區域變數的名字,那你遇到另一個問題, 被稱為
函式成長賀爾蒙失調症. 請參考下一章說明.
第四章: 函式
函式必須短小可愛, 並且只做一件事. 它們應該能夠塞進一或兩頁
的螢幕裡去(我們都知道ISO/ANSI標準螢幕大小是80x24), 且只做一件
事, 並且要做的好.
一個函式的(可允許的)最大長度是和其複雜度及縮格的程度成反比. 所以如
果你有一個觀念上簡單的函式,卻是一個長的(但是簡單的)case敘述, 其
中你須要對許多不同的情況做許多的小處理, 那麼函式長一點沒有關係.
不過,如果你有一個複雜的函式, 而你覺得可能一般程度的高一學生就
無法了解這個函式在幹麻, 你可能更需要更嚴格的遵守最大長度的限制.
使用名字較有意義的輔助函式(helper functions) (如果這個函式對效率
的要求很高的話, 你可以要求編譯器把這些輔助函式當作in-line function
展開, 而且編譯器可能可以做的比你自己手工做來的好)
另外一個評量函式的方法是區域變數的數量. 它們不應該超過5-10個,
不然你可能做錯了什麼事. 重新構思一下這個函式, 然後把它切成幾個
小塊. 人腦一般可以輕易的處理七件事,超過這個數量就會搞亂了.
你知道你很聰明, 但是兩個禮拜後你可能還想了解你現在做了什麼.
第五章: 註解
註解是件好事, 但是也有過份註解的危險. 絕對不要在註解內試著解釋
你的碼是如何工作的: 這還不如把程式寫得清楚點, 一看就知道它在幹麻,
而且解釋一段亂寫的碼是件浪廢時間的事.
大致而言, 你要你的註解說明你的程式做了什麼, 而不是如何做.
並且, 試著避免在函式裡面放註釋: 如果你的程式複雜到需要
對部份的內容做註解, 你可能需要再花點時間重看第四章. 你
可以放些小註解來解釋或警告一些特別的小聰明(或醜陋的)地方,
但是儘量避免過份使用. 正確的作法應是把註解放在函式開頭的地
方, 告訴他人它要作什麼, 可能還要說明為什麼要做這些事.
第六章: 你把程式弄的亂七八糟了
沒關係, 我們都會遇到這種問題. 可能有unix老手已經告訴
過你 "GNU emacs" 可以自動的幫你重排C 的程式碼, 而你也發
現它的確會做, 但是它的預設值有點令人不滿意(事實上, 這些值
還比打字亂打糟糕 - 在GNU emacs上任意的亂打還是造不出好程式的)
所以, 你可以把GNU emacs丟掉,或者設定一些較合理的預設值. 後者
可以把下面這些碼放到你的.emacs檔達成:
(defun linux-c-mode ()
"C mode with adjusted defaults for use with the Linux kernel."
(interactive)
(c-mode)
(c-set-style "K&R")
(setq c-basic-offset 8))
這樣定義了 M-x linux-c-mode 指令. 當你 hack 某個模組時, 如果
你在前兩行的任意地方放 -*- linux-c -*- 這個字串, 這個模式就
會自動的起動. 同時, 你也可能想要加這行:
(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
auto-mode-alist))
到你的.emacs檔去, 如果當你編輯/usr/src/linux下的程式檔的時後, 想讓
linux-c-mode自動起動的話.
不過僅管你還是不能利用emacs作合理的重排的話, 你還沒絕望: 使用 "indent".
這裡又遇到同樣的問題. GNU indent和GNU emacs有同樣的白癡設定, 這就
是為什麼你須要給它一些命令列選項的原因. 還好, 這不會太麻煩, 因為
連GNU indent的作者也體認到K&R的權威性 (GNU的人不壞, 他們在這方
面只是被嚴重的誤導了罷了), 所以你只要給indent這樣的選項 "-kr -i8"
即可(表示 "K&R, 八格的縮格").
"indent" 有許多的選項,特別是預到重排註解的時候, 你可能需要看一下
使用手冊. 不過要記得: "indent" 不是修理不良程式碼的工具.