linux內核的編碼是一種極端情況。
需要清晰明朗以供全世界的開發者學習、修改,對代碼的質量要求較高。
相信linus大神在長期接觸各種各式代碼後脾氣會變得更暴躁,就比如前段時間在某論壇痛斥C++。。。
節選,去除不適合PHP程序員閱讀的部分。
如果你開發PHP程序的核心代碼,比如框架,尤其建議好好思考。
雖然,它和一些權威的代碼規范比如discuz和zend的有所沖突,但是依然能從中受益。
linux kernel coding style (針對PHPer作了節選)
linux kernel coding style的中文譯者:
中文版維護者: 張樂 Zhang Le
中文版翻譯者: 張樂 Zhang Le
中文版校譯者: 王聰 Wang Cong
wheelz
管旭東 Xudong Guan
Li Zefan
Wang Chen
第一章:縮進
制表符是8個字符,所以縮進也是8個字符。有些異端運動試圖將縮進變為4(乃至2)個字符深,這幾乎相當於嘗試將圓周率的值定義為3。
理由:縮進的全部意義就在於清楚的定義一個控制塊起止於何處。尤其是當你盯著你的屏幕連續看了20小時之後,你將會發現大一點的縮進會使你更容易分辨縮進。
現在,有些人會抱怨8個字符的縮進會使代碼向右邊移動的太遠,在80個字符的終端屏幕上就很難讀這樣的代碼。這個問題的答案是,如果你需要3級以上的縮進,不管用何種方式你的代碼已經有問題了,應該修正你的程序。
在switch語句中消除多級縮進的首選的方式是讓“switch”和從屬於它的“case”標簽對齊於同一列,而不要“兩次縮進”“case”標簽。比如:
C++代碼
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;
}
不要把多個語句放在一行裡,除非你有什麼東西要隱藏:
C++代碼
if (condition) do_this;
do_something_everytime;
也不要在一行裡放多個賦值語句。內核代碼風格超級簡單。就是避免可能導致別人誤讀的表達式。
除了注釋、文檔和Kconfig之外,不要使用空格來縮進,前面的例子是例外,是有意為之。
選用一個好的編輯器,不要在行尾留空格。
第二章:把長的行和字符串打散
代碼風格的意義就在於使用平常使用的工具來維持代碼的可讀性和可維護性。
每一行的長度的限制是80列,我們強烈建議您遵守這個慣例。
長於80列的語句要打散成有意義的片段。每個片段要明顯短於原來的語句,而且放置的位置也明顯的靠右。同樣的規則也適用於有很長參數列表的函數頭。長字符串也要打散成較短的字符串。唯一的例外是超過80列可以大幅度提高可讀性並且不會隱藏信息的情況。
C++代碼
void fun(int a, int b, int c)
{
if (condition)
printk(KERN_WARNING "Warning this is a long "
"3 parameters a: %u b: %u "
"c: %u ", a, b, c);
else
next_statement;
}
第三章:大括號和空格的放置
C語言風格中另外一個常見問題是大括號的放置。和縮進大小不同,選擇或棄用某種放置策略並沒有多少技術上的原因,不過首選的方式,就像Kernighan和Ritchie展示給我們的,是把起始大括號放在行尾,而把結束大括號放在行首,所以:
C++代碼
if (x is true) {
we do y
}
這適用於所有的非函數語句塊(if、switch、for、while、do)。比如:
C++代碼
switch (action) {
case KOBJ_ADD:
return "add";
case KOBJ_REMOVE:
return "remove";
case KOBJ_CHANGE:
return "change";
default:
return NULL;
}
不過,有一個例外,那就是函數:函數的起始大括號放置於下一行的開頭,所以:
C++代碼
int function(int x)
{
body of function
}
全世界的異端可能會抱怨這個不一致性是……呃……不一致的,不過所有思維健全的人都知道(a)K&R是_正確的_,並且(b)K&R是正確的。此外,不管怎樣函數都是特殊的(在C語言中,函數是不能嵌套的)。
注意結束大括號獨自占據一行,除非它後面跟著同一個語句的剩余部分,也就是do語句中的“while”或者if語句中的“else”,像這樣:
C++代碼
do {
body of do-loop
} while (condition);
和
C++代碼
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
理由:K&R。
也請注意這種大括號的放置方式也能使空(或者差不多空的)行的數量最小化,同時不失可讀性。因此,由於你的屏幕上的新行是不可再生資源(想想25行的終端屏幕),你將會有更多的空行來放置注釋。
當只有一個單獨的語句的時候,不用加不必要的大括號。
C++代碼
if (condition)
action();
這點不適用於本身為某個條件語句的一個分支的單獨語句。這時需要在兩個分支裡都使用大括號。
C++代碼
if (condition) {
do_this();
do_that();
} else {
otherwise();
}
3.1:空格
Linux內核的空格使用方式(主要)取決於它是用於函數還是關鍵字。(大多數)關鍵字後要加一個空格。值得注意的例外是sizeof、typeof、alignof和__attribute__,這些關鍵字某些程度上看起來更像函數(它們在Linux裡也常常伴隨小括號而使用,盡管在C語言裡這樣的小括號不是必需的,就像“struct fileinfo info”聲明過後的“sizeof info”)。
所以在這些關鍵字之後放一個空格:
if, switch, case, for, do, while
但是不要在sizeof、typeof、alignof或者__attribute__這些關鍵字之後放空格。例如,
C++代碼
s = sizeof(struct file);
不要在小括號裡的表達式兩側加空格。這是一個反例:
C++代碼
s = sizeof( struct file );
當聲明指針類型或者返回指針類型的函數時,“*”的首選使用方式是使之靠近變量名或者函
數名,而不是靠近類型名。例子:
C++代碼
char *linux_banner;
unsigned long long memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
在大多數二元和三元操作符兩側使用一個空格,例如下面所有這些操作符:
C++代碼
= + - < > * / % | & ^ <= >= == != ? :
但是一元操作符後不要加空格:
C++代碼
& * + - ~ ! sizeof typeof alignof __attribute__ defined
後綴自加和自減一元操作符前不加空格:
++ --
前綴自加和自減一元操作符後不加空格:
++ --
“.”和“->”結構體成員操作符前後不加空格。
不要在行尾留空白。有些可以自動縮進的編輯器會在新行的行首加入適量的空白,然後你就可以直接在那一行輸入代碼。不過假如你最後沒有在那一行輸入代碼,有些編輯器就不會移除已經加入的空白,就像你故意留下一個只有空白的行。包含行尾空白的行就這樣產生了。
當git發現補丁包含了行尾空白的時候會警告你,並且可以應你的要求去掉行尾空白;不過如果你是正在打一系列補丁,這樣做會導致後面的補丁失敗,因為你改變了補丁的上下文。
第四章:命名
C是一個簡樸的語言,你的命名也應該這樣。和Modula-2和Pascal程序員不同,C程序員不使用類似 ThisVariableIsATemporaryCounter 這樣華麗的名字。C程序員會稱那個變量為“tmp”,這樣寫起來會更容易,而且至少不會令其難於理解。
不過,雖然混用大小寫的名字是不提倡使用的,但是全局變量還是需要一個具描述性的名字。稱一個全局函數為“foo”是一個難以饒恕的錯誤。
全局變量(只有當你真正需要它們的時候再用它)需要有一個具描述性的名字,就像全局函數。如果你有一個可以計算活動用戶數量的函數,你應該叫它“count_active_users()”或者類似的名字,你不應該叫它“cntuser()”。
在函數名中包含函數類型(所謂的匈牙利命名法)是腦子出了問題——編譯器知道那些類型而且能夠檢查那些類型,這樣做只能把程序員弄糊塗了。難怪微軟總是制造出有問題的程序。
本地變量名應該簡短,而且能夠表達相關的含義。如果你有一些隨機的整數型的循環計數器,它應該被稱為“i”。叫它“loop_counter”並無益處,如果它沒有被誤解的可能的話。類似的,“tmp”可以用來稱呼任意類型的臨時變量。
如