最近在向Linux內核提交一些驅動程序,在提交的過程當中,發現本身的代碼離Linux內核的coding style要求仍是差不少。當初本身對內核文檔裏的CodingStyle一文只是粗略的瀏覽,真正寫代碼的時候在不少細節上會照顧不周。不過, 在不遵照規則的程序員隊伍裏,我並非孤獨的。若是去看drivers/staging下的代碼,就會發現不少驅動程序都沒有嚴格遵照內核的coding style,並且在不少驅動程序的TODO文件裏,都會把"checkpatch.pl fixes"做爲本身的目標之一(checkpatch.pl是用來檢查代碼是否符合coding style的腳本)。linux
不能否認,coding style是仁者見仁、智者見智的事情。好比Microsoft所推崇的匈牙利命名法,在Linus看來就是及其腦殘(brain damaged)的作法。也許您並不同意Linus制定的coding style,但在提交內核驅動這件事上,最好仍是以大局爲重。對於這麼一個龐大的集市式的開發來講,隨意書寫代碼必將帶來嚴重的可維護性的災難。程序員
一些輔助工具
當代碼量達到必定程度時,手動去檢查和修改coding style是很是繁瑣的工做,幸虧,咱們還有一些工具可使用。編輯器
scripts/checkpatch.pl
這是一個檢查代碼是否符合內核編碼規範的的腳本。顧名思義,checkpatch是用來檢查patch的,默認的調用也確實如此。若是用來檢查原文件,須要加上「-f」的選項。ide
咱們來看一段無聊的代碼(文件名爲print_msg.c):函數
1
2
3
4
5
6
7
8
9
10
11
12
|
void
print_msg(
int
a)
{
switch
(a) {
case
1:
printf
(
"a == 1\n"
);
break
;
case
2:
printf
(
"a == 2\n"
);
break
;
}
}
|
這段代碼的coding style是否有問題呢?用checkpatch.pl來檢查一下:工具
scripts/checkpatch.pl -f print_msg.cpost
檢查的結果是:ui
ERROR: switch and case should be at the same indent
#3: FILE: switch.c:3:
+ switch (a) {
+ case 1:
[...]
+ case 2:
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要求有相同的縮進。本例的代碼不多,錯誤也只有這一個,手動修改很方便。若是相似的縮緊錯誤不少怎麼辦?this
scripts/Lindent
scripts目錄下的工具Lindent能夠用來自動修改縮進問題。提醒一下,使用Lindent要求系統安裝indent這個工具。
對於上面這個例子,執行Lindent命令:
scripts/Lindent print_msg.c
獲得的新代碼是:
1
2
3
4
5
6
7
8
9
10
11
12
|
void
print_msg(
int
a)
{
switch
(a) {
case
1:
printf
(
"a == 1\n"
);
break
;
case
2:
printf
(
"a == 2\n"
);
break
;
}
}
|
sed
sed是一個流編輯器,其強大的功能能夠幫助咱們處理不少重複性的工做。好比,Linux內核的coding style要求,行尾不能有空格(包括Tab),去除這些空格就能夠藉助sed。
我本身的習慣不好,常常在代碼的行尾留下一些空格。好比一行代碼過長鬚要換行時,老是下意識的在換行的地方敲一個空格。另外,我經常使用的編輯器之一的Kate,爲了對齊的須要,常常在空行的前面留上幾個縮進的Tab(以下圖)。
手動去除這些行尾的空格是一件頭大的事情,但對於sed來講不過是舉手之勞。命令格式以下:
sed 's/[ \t]*$//g' your_code.c
一些須要注意的Coding Style
縮進
一、除了註釋、文檔和Kconfig以外,使用Tab縮進,而不是空格,而且Tab的寬度爲8個字符;
二、switch ... case ...語句中,switch和case具備相同的縮進(參考上文);
花括號
三、花括號的使用參考K&R風格。
若是是函數,左花括號另起一行:
1
2
3
4
|
int
function(
int
x)
{
body of function
}
|
不然,花括號緊接在語句的最後:
1
2
3
|
if
(x is
true
) {
we
do
y
}
|
若是隻有一行語句,則不須要用花括號:
1
2
|
if
(condition)
action();
|
可是,對於條件語句來講,若是一個分支是一行語句,另外一個分支是多行,則須要保持一致,使用花括號:
1
2
3
4
5
6
|
if
(condition) {
do_this();
do_that();
}
else
{
otherwise();
}
|
空格
四、在關鍵字「if, switch, case, for, do, while」以後須要加上空格,如:
1
|
if
(something)
|
五、在關鍵字「sizeof, typeof, alignof, or __attribute__」以後不要加空格,如:
1
|
sizeof
(
struct
file)
|
六、在括號裏的表達式兩邊不要加空格,好比,下面是一個反面的例子:
1
|
sizeof
(
struct
file )
|
七、大多說的二元和三元運算符兩邊須要空格,如「= + - < > * / % | & ^ <= >= == != ? :」;
八、一元運算符後面不要空格,如「& * + - ~ ! sizeof typeof alignof __attribute__ defined」;
九、在前綴自增自減運算符以後和後綴自增自減運算符以前不須要空格(「++」和「--」);
十、結構成員運算符(「.」和「->」)的兩邊不須要空格;
十一、行尾不須要空格;
註釋
十二、使用C89的「/* ... */」風格而不是C99的「// ...」風格;
1三、對於多行註釋,能夠參考下例:
1
2
3
4
5
6
7
8
|
/*
* This is the preferred style for multi-line
* comments in the Linux kernel source code.
* Please use it consistently.
*
* Description: A column of asterisks on the left side,
* with beginning and ending almost-blank lines.
*/
|
Kconfig
1四、「config」定義下面的語句用Tab縮進,help下面的語句再額外縮進兩個空格,如:
1
2
3
4
5
6
7
8
|
config AUDIT
bool "Auditing support"
depends on NET
help
Enable auditing infrastructure that can be used with another
kernel subsystem, such as SELinux (which requires this for
logging of avc messages output). Does not do system-call
auditing without CONFIG_AUDITSYSCALL.
|
宏
1五、多行的宏定義須要用「do .. while」封裝,如:
1
2
3
4
5
|
#define macrofun(a, b, c) \
do
{ \
if
(a == 5) \
do_this(b, c); \
}
while
(0)
|
函數返回值
1六、函數返回值的定義最好也要遵循必定的章法。
若是函數的名稱是一種動做或者命令式的語句,應該以錯誤代碼的形式返回(一般是0表示成功,-Exxx這種形式的負數表示錯誤),如:
1
|
do_something()
|
若是函數的名稱是判斷語句,則返回值應該相似與布爾值(一般1表示成功,0表示錯誤),如:
1
|
something_is_present()
|
【參考資料】
(2) http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/