天天看點

談談為 Linux 核心寫驅動的編碼規範

最近在向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,但在送出核心驅動這件事上,最好還是以大局為重。對于這麼一個龐大的集市式的開發來說,随意書寫代碼必将帶來嚴重的可維護性的災難。

談談為 Linux 核心寫驅動的編碼規範

(題圖來自:mota.ru)

<a target="_blank"></a>

當代碼量達到一定程度時,手動去檢查和修改coding style是非常繁瑣的工作,幸好,我們還有一些工具可以使用。

這是一個檢查代碼是否符合核心編碼規範的的腳本。顧名思義,checkpatch是用來檢查patch的,預設的調用也确實如此。如果用來檢查原檔案,需要加上“-f”的選項。

我們來看一段無聊的代碼(檔案名為print_msg.c):

<code>void print_msg(int a)</code>

<code>{</code>

<code>switch (a) {</code>

<code>case 1:</code>

<code>printf("a == 1\n");</code>

<code>break;</code>

<code></code>

<code>case 2:</code>

<code>printf("a == 2\n");</code>

<code>}</code>

這段代碼的coding style是否有問題呢?用checkpatch.pl來檢查一下:

<code>scripts/checkpatch.pl -f  print_msg.c</code>

檢查的結果是:

<code>error: switch and case should be at the same indent</code>

<code>#3: file: switch.c:3:</code>

<code>+ switch (a) {</code>

<code>+ case 1:</code>

<code>[...]</code>

<code>+ case 2:</code>

<code>total: 1 errors, 0 warnings, 12 lines checked</code>

<code>switch.c has style problems, please review. if any of these errors</code>

<code>are false positives report them to the maintainer, see</code>

<code>checkpatch in maintainers.</code>

在linux核心的coding style裡,switch和case要求有相同的縮進。本例的代碼很少,錯誤也隻有這一個,手動修改很友善。如果類似的縮緊錯誤很多怎麼辦?

scripts目錄下的工具lindent可以用來自動修改縮進問題。提醒一下,使用lindent要求系統安裝indent這個工具。

對于上面這個例子,執行lindent指令:

<code>scripts/lindent print_msg.c</code>

得到的新代碼是:

sed是一個流編輯器,其強大的功能可以幫助我們處理很多重複性的工作。比如,linux核心的coding style要求,行尾不能有空格(包括tab),去除這些空格就可以借助sed。

我自己的習慣很差,經常在代碼的行尾留下一些空格。比如一行代碼過長需要換行時,總是下意識的在換行的地方敲一個空格。另外,我常用的編輯器之一的kate,為了對齊的需要,經常在空行的前面留上幾個縮進的tab(如下圖)。

談談為 Linux 核心寫驅動的編碼規範

手動去除這些行尾的空格是一件頭大的事情,但對于sed來說不過是舉手之勞。指令格式如下:

<code>sed 's/[ \t]*$//g' your_code.c</code>

1、除了注釋、文檔和kconfig之外,使用tab縮進,而不是空格,并且tab的寬度為8個字元;

2、switch ... case ...語句中,switch和case具有相同的縮進(參考上文);

3、花括号的使用參考k&amp;r風格。

如果是函數,左花括号另起一行:

<code>int function(int x)</code>

<code>body of function</code>

否則,花括号緊接在語句的最後:

<code>if (x is true) {</code>

<code>we do y</code>

如果隻有一行語句,則不需要用花括号:

<code>if (condition)</code>

<code>action();</code>

但是,對于條件語句來說,如果一個分支是一行語句,另一個分支是多行,則需要保持一緻,使用花括号:

<code>if (condition) {</code>

<code>do_this();</code>

<code>do_that();</code>

<code>} else {</code>

<code>otherwise();</code>

4、在關鍵字“if, switch, case, for, do, while”之後需要加上空格,如:

<code>if (something)</code>

5、在關鍵字“sizeof, typeof, alignof, or __attribute__”之後不要加空格,如:

<code>sizeof(struct file)</code>

6、在括号裡的表達式兩邊不要加空格,比如,下面是一個反面的例子:

<code>sizeof( struct file )</code>

7、大多說的二進制和三元運算符兩邊需要空格,如“= + - &lt; &gt; * / % | &amp; ^ &lt;= &gt;= == != ? :”;

8、一進制運算符後面不要空格,如“&amp; * + - ~ ! sizeof typeof alignof __attribute__ defined”;

9、在字首自增自減運算符之後和字尾自增自減運算符之前不需要空格(“++”和“--”);

10、結構成員運算符(“.”和“-&gt;”)的兩邊不需要空格;

11、行尾不需要空格;

12、使用c89的“/* ... */”風格而不是c99的“// ...”風格;

13、對于多行注釋,可以參考下例:

<code>/*</code>

<code>* this is the preferred style for multi-line</code>

<code>* comments in the linux kernel source code.</code>

<code>* please use it consistently.</code>

<code>*</code>

<code>* description: a column of asterisks on the left side,</code>

<code>* with beginning and ending almost-blank lines.</code>

<code>*/</code>

14、“config”定義下面的語句用tab縮進,help下面的語句再額外縮進兩個空格,如:

<code>config audit</code>

<code>bool "auditing support"</code>

<code>depends on net</code>

<code>help</code>

<code>enable auditing infrastructure that can be used with another</code>

<code>kernel subsystem, such as selinux (which requires this for</code>

<code>logging of avc messages output). does not do system-call</code>

<code>auditing without config_auditsyscall.</code>

15、多行的宏定義需要用“do .. while”封裝,如:

<code>#define macrofun(a, b, c) \</code>

<code>do { \</code>

<code>if (a == 5) \</code>

<code>do_this(b, c); \</code>

<code>} while (0)</code>

16、函數傳回值的定義最好也要遵循一定的章法。

如果函數的名稱是一種動作或者指令式的語句,應該以錯誤代碼的形式傳回(通常是0表示成功,-exxx這種形式的負數表示錯誤),如:

<code>do_something()</code>

如果函數的名稱是判斷語句,則傳回值應該類似與布爾值(通常1表示成功,0表示錯誤),如:

<code>something_is_present()</code>

<b>原文釋出時間為:2015-07-30</b>

<b></b>

<b>本文來自雲栖社群合作夥伴“linux中國</b>

繼續閱讀