發信人: syc@cc.ntu.edu.tw (Shiau Yong-Ching), 看板: Linux 
標  題: Linux程式設計規範 
發信站: National Taiwan University (Wed Oct  1 10:06:43 1997) 
轉信站: fromzero!netnews.ntu!not-for-mail 

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" 不是修理不良程式碼的工具. 

Shiau Yong-Ching                 Sendmail Club...