以下內容及範例皆取自Linus所寫的 Linux kernel coding style。另外,Linus文筆雄『賤』有力,如果我的摘要有那麼一點點不討喜,那一定跟原文比較有關,跟翻譯無關。
1. 縮排
所有的縮排皆用8個字元tab。
原因:你每天連續看二十個小時code的話,你就會知道為何要用大尺寸縮排了!有人會抱怨大尺寸縮排會讓code一直偏向右移,在80字元寬的terminal上不好讀。Linus曰:如果你的程式用到三層以上的縮排,你的程式大概也好不到哪去,快點修修吧!
別把兩個statement放同一行。
別在同一行用 multiple assignment,kernel code就是要簡單,別搞花俏。
用個好一點editor,別在檔案結尾加任何空行。
switch 和 case 放在同一層縮排,如下:
switch (suffix) {
case 'G':
case 'g':
mem <<= 30;
break;
case 'M':
case 'm':
mem <<= 20;
break;
case 'K':
case 'k':
mem <<= 10;
/* fall through */
default:
break;
}
2. 分割過長的一行code及字串
每行限制80個字元。超過的話請自行分割,分割後的部份儘量往右縮排,這樣能一眼辨別這是一行code分割的結果。function header亦同。void fun(int a, int b, int c) { if (condition) printk(KERN_WARNING "Warning this is a long printk with " "3 parameters a: %u b: %u " "c: %u \n", a, b, c); else next_statement; }
3. 括號和空格
用K&R style的括號– 左括號放在行尾,又括號放在另一行,如下if (x is true) { we do y } switch (action) { case KOBJ_ADD: return "add"; case KOBJ_REMOVE: return "remove"; case KOBJ_CHANGE: return "change"; default: return NULL; }例外是function,左右兩個括號都放在各自一行的行首:
int function(int x) { body of function }do...while和多個if..else...也是例外:
do { body of do-loop } while (condition);
if (x == y) { .. } else if (x > y) { ... } else { .... }if...else...後的 statement只有一個,不需加括號:
if (condition) action(); if (condition) do_this(); else do_that();但是if...else...只要有任何分支用了括號,兩個分支都要用括號:
if (condition) { do_this(); do_that(); } else { otherwise(); }
3.1: 空白字元
基本原則是,(大部分的)keyword後都要加上空白字元,例如:if, switch, case, for, do, while。但是『長得像function』的keyword後面不需加空白,例如:sizeof, typeof, alignof, __attribute_。括號內不需要空白: s = sizeof( struct file ); /* BAD!!! */
宣告pointer時,空白放在*之前: char *linux;
binary/ternary operator前後都加空白:
= + - < > * / % | & ^ <= >= == != ? :
unary operator 前後則免:
& * + - ~ ! sizeof typeof alignof __attribute__ defined
這些也不用:
a++; --a; my_struct.b; my_ptr->size;
行末不要有多餘空白。有些編輯器有smart indent功能,只要一按enter就自動預先填好indent tab,這種空白可以接受。但smart indent若是在檔案最末端則不OK。
4. 命名
C是種鐵血斯巴達式的語言,不像Modula-2或是pascal會用到ThisVariableIsATemporaryCounter這種裝可愛的命名法。直接用tmp就可以了,因為它好寫又易懂。Global vairable的命名必須能精確敘述他的用途。例如:
count_active_user(); /* good */ cntusr(); /* BAD */把data type放進命名規則中(匈牙利命名法)的人一定是腦袋有問題,compiler本來就知道各個變數的data type了,何必在放在變數名中讓事情弄得更複雜。難怪Microsoft的程式很多bug。
Local variable的命名則要短又有力。用 i 當作loop counter就是一個好例子,用 loop_counter這個名字就遜了。
5. Typedefs
不要刻意把某個struct或是pointer用typedef的方式另外命名。是這行比較易懂?
vps_t a;還是這行?
struct virtual_container* a;
typedef只適用於:
- 你需要把所有內部細節隱藏在 opaque object 中,外人只能經由 access functions 操作。
- 分辨不同長度的integer type,例如:u8/u16/u32
- 用到 sparse 來作 type-checking
- (跟2雷同,譯者略)
- 某些結構會和 user space 共用,但既不能直接用C99的data type,也不能用kernel自行定義的 u32,所以只好訂個 __u32。(譯者自己不懂這段的意思,有人可以解釋嗎?)
總而言之,struct 內部若可直接被外界存取,就不要再去typedef。沒有適當理由,不要隨便亂用typedef。
6. Functions
function要短要甜而且只做一件事,內容要可以在一兩頁內顯示完畢。80x24是一頁,你知道的。function可接受的最大長度是和複雜度成反比的,所以一個function中只有一個超大switch但每個case都超簡單,那沒問題,全部放在一個function。反之,如果你的function有點複雜度,沒天份的高一學生可能很難了解其中的奧妙,那請嚴格遵守最大長度限制。
一個不錯的指標是在單一function中不應該會使用超過5~10個 local variable。而且人腦一次只能追蹤7件不同的東西,太多東西搞在一起一定會搞砸。
程式碼中function和function必須間隔一行。如果用到 EXPORT_* macro,請緊跟在function後:
int system_is_up(void) { return system_state == SYSTEM_RUNNING; } EXPORT_SYMBOL(system_is_up);
Hi, 剛好路過,發現照片有點像小學同學耶! 你不會恰好是永和國小畢吧!!
回覆刪除我就是永和國小畢業的耶, 我是梁書豪, 敢問你是? 寄信給我吧!
刪除哈..還真是有緣ㄚ,我是王鵬超,mail : tomy.wang.1@gmail.com
刪除哈, 真巧. 我是賣菜的小菜ㄈ, 國小ㄅ葉就很少遇到同學. 書豪是國立大學ㄅ葉, 真利害. 超王他家來買菜時, 聽他家人說, 也是國立大學ㄅ葉, 在竹科大公司上班, 股票2, 3百, 真是一個比一個利害.
回覆刪除switch 的 csae 好像多了一層縮排耶
回覆刪除感謝指點,已修正
刪除作者已經移除這則留言。
回覆刪除受益良多 謝謝!!
回覆刪除