源出處:http://top.akaedu.org/index.php/index/bookdetail/id/2890
最近在向Linux內核提交一些驅動程序,在提交的過程中,發現自己的代碼離Linux內核的coding style要求還是差很多。當初自己對內核文檔裏的CodingStyle一文只是粗略的瀏覽,真正寫代碼的時候在很多細節上會照顧不周。不過, 在不遵守規則的程序員隊伍裏,我並不是孤獨的。如果去看drivers/staging下的代碼,就會發現很多驅動程序都沒有嚴格遵守內核的coding
style,而且在很多驅動程序的TODO文件裏,都會把"checkpatch.pl fixes"作爲自己的目標之一(checkpatch.pl是用來檢查代碼是否符合coding style的腳本)。
不可否認,coding style是仁者見仁、智者見智的事情。比如Microsoft所推崇的匈牙利命名法,在Linus看來就是及其腦殘(brain damaged)的做法。也許您並不贊成Linus制定的coding style,但在提交內核驅動這件事上,最好還是以大局爲重。對於這麼一個龐大的集市式的開發來說,隨意書寫代碼必將帶來嚴重的可維護性的災難。
一些輔助工具
當代碼量達到一定程度時,手動去檢查和修改coding style是非常繁瑣的工作,幸好,我們還有一些工具可以使用。
scripts/checkpatch.pl
這是一個檢查代碼是否符合內核編碼規範的的腳本。顧名思義,checkpatch是用來檢查patch的,默認的調用也確實如此。如果用來檢查原文件,需要加上“-f”的選項。
我們來看一段無聊的代碼(文件名爲print_msg.c):
這段代碼的coding style是否有問題呢?用checkpatch.pl來檢查一下:
scripts/checkpatch.pl -f print_msg.c
檢查的結果是:
ERROR: switch and case should be at the same indent |
total: 1 errors, 0 warnings, 12 lines checked |
switch.c has style problems, please review. If any of these errors |
are false positives report them to the maintainer, see |
CHECKPATCH in MAINTAINERS. |
在Linux內核的coding style裏,switch和case要求有相同的縮進。本例的代碼很少,錯誤也只有這一個,手動修改很方便。如果類似的縮緊錯誤很多怎麼辦?
scripts/Lindent
scripts目錄下的工具Lindent可以用來自動修改縮進問題。提醒一下,使用Lindent要求系統安裝indent這個工具。
對於上面這個例子,執行Lindent命令:
scripts/Lindent print_msg.c
得到的新代碼是:
sed
sed是一個流編輯器,其強大的功能可以幫助我們處理很多重複性的工作。比如,Linux內核的coding style要求,行尾不能有空格(包括Tab),去除這些空格就可以藉助sed。
我自己的習慣很差,經常在代碼的行尾留下一些空格。比如一行代碼過長需要換行時,總是下意識的在換行的地方敲一個空格。另外,我常用的編輯器之一的Kate,爲了對齊的需要,經常在空行的前面留上幾個縮進的Tab(如下圖)。
手動去除這些行尾的空格是一件頭大的事情,但對於sed來說不過是舉手之勞。命令格式如下:
sed 's/[ \t]*$//g' your_code.c
一些需要注意的Coding Style
縮進
1、除了註釋、文檔和Kconfig之外,使用Tab縮進,而不是空格,並且Tab的寬度爲8個字符;
2、switch ... case ...語句中,switch和case具有相同的縮進(參考上文);
花括號
3、花括號的使用參考K&R風格。
如果是函數,左花括號另起一行:
否則,花括號緊接在語句的最後:
如果只有一行語句,則不需要用花括號:
但是,對於條件語句來說,如果一個分支是一行語句,另一個分支是多行,則需要保持一致,使用花括號:
空格
4、在關鍵字“if, switch, case, for, do, while”之後需要加上空格,如:
5、在關鍵字“sizeof, typeof, alignof, or __attribute__”之後不要加空格,如:
6、在括號裏的表達式兩邊不要加空格,比如,下面是一個反面的例子:
7、大多說的二元和三元運算符兩邊需要空格,如“= + - < > * / % | & ^ <= >= == != ? :”;
8、一元運算符後面不要空格,如“& * + - ~ ! sizeof typeof alignof __attribute__ defined”;
9、在前綴自增自減運算符之後和後綴自增自減運算符之前不需要空格(“++”和“--”);
10、結構成員運算符(“.”和“->”)的兩邊不需要空格;
11、行尾不需要空格;
註釋
12、使用C89的“/* ... */”風格而不是C99的“// ...”風格;
13、對於多行註釋,可以參考下例:
Kconfig
14、“config”定義下面的語句用Tab縮進,help下面的語句再額外縮進兩個空格,如:
2 |
bool "Auditing support" |
5 |
Enable auditing infrastructure that can be used with another |
6 |
kernel subsystem, such as SELinux (which requires this for |
7 |
logging of avc messages output). Does not do system-call |
8 |
auditing without CONFIG_AUDITSYSCALL. |
宏
15、多行的宏定義需要用“do .. while”封裝,如:
1 |
#define macrofun(a, b, c) \ |
函數返回值
16、函數返回值的定義最好也要遵循一定的章法。
如果函數的名稱是一種動作或者命令式的語句,應該以錯誤代碼的形式返回(通常是0表示成功,-Exxx這種形式的負數表示錯誤),如:
如果函數的名稱是判斷語句,則返回值應該類似與布爾值(通常1表示成功,0表示錯誤),如: