Linux有獨特的編程風格,在內核源代碼目錄Documentation/CodingStyle,詳細描述代碼風格。
建議大家可以去看一下,老外寫技術文檔還是很有意思的,上來就狂噴,“你不這樣寫就會完蛋,異教徒才不這樣寫……”,沒有國內那么刻板,多閱讀英語文檔對技術增長很有幫助。
1. 命名規范
在一般編程中,習慣以如下方式命名宏、變量和函數:
#define PI 3.1415926 /*用大寫字母代表宏 */
int minValue, maxValue; /*變量:第一個單詞全小寫,其后單詞的第一個字母大寫*/
void SendData (void); /* 函數:所有單詞第一個字母都大寫 */
這種通過單詞之間通過首字母大寫來區分的方式非常流行。通過第1個單詞的首字母是否大寫可以區分名稱屬于變量還是屬于函數,而看到整串的大寫字母可以斷定為宏。
許多領域的程序開發都遵照此習慣。
但是Linux不以這種習慣命名,對于上面的一段程序,在Linux中它會被命名為:
#define PI 3.1415926
int min_value, max_value;
void send_data (void);
在上述命名方式中,宏還是一樣用大寫,但變量和函數名,不按照Windows所采用的用首字母大寫來區分單詞,而是采用下劃線。而且Linux下命名,全局變量命名最好用長的準確的描述,局部變量最好簡短,甚至直接用tmp,i之類的。
其實兩種命名方式都行,寫Liunx下的程序時,與Linux社區代碼風格一致更好,但你用第一種我覺得也無傷大雅。
2.縮進
縮進統一使用"TAB",而不是空格括號。
另外提一句:在Linux下,"TAB"代表8個字符,而不是4個,Linux代碼風格認為8個字符更能體現層次結構。文檔里噴"TAB"為4字符的是異教徒,對于8字符在多層次時,代碼太偏右的問題,文檔又噴層次超過三層,你的代碼就會完蛋,哈哈哈。
為了減少層次,在switch/case語句方面, Linux 建議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;
}
3. Linux中代碼括號“{”和“}”的使用原則
1)對于結構體、if/for/while/switch語句, “{”不另起一行,例如:
struct var_data {
int len;
char data[0];
};
if (a == b) {
a = c;
d = a;
}
for (i = 0; i < 10; i++) {
a = c;
d = a;
}
2)如果if、for循環后只有1行,不要加“{”和“}”,例如:
for (i = 0; i < 10; i++) {
a = c;
}
應該改為:
for (i = 0; i < 10; i++)
a=c;
- if和else混用的情況下, else語句不另起一行,例如:
if (x == y){
...
} else if (x > y) {
...
} else {
...
}
4)對于函數, “{”另起一行,例如:
int add (int a, int b)
[
return a + b;
}
4. 空格的使用
1)關鍵字后加空格
在這些關鍵字后面加空格:
if, switch, case, for, do, while
但是這些不加:
sizeof, typeof, alignof, attribute
例如:
s = sizeof(struct file);
2)括號內,緊挨著括號不加空格
錯誤示范:
s = sizeof( struct file );
3)對于指針,”*“號挨著名字而不是類型
例如:
char *linux_banner;
unsigned long long memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
4)操作符兩側加空格
以下二元或三元操作符兩側要加空格:
= + - < > * / % | & ^ <= >= == != ? :
但是以下一元操作符,不加空格:
& * + - ~ ! sizeof typeof alignof attribute defined
自增自減符號。不加空格:
++ --
結構體成員操作符,不加空格:
'.' 和 "->"
不要在行尾加空格。
5. 函數
函數應該簡潔明了,只做一件事。函數長度應該控制在一到兩個屏幕顯示范圍內(ISO/ANSI屏幕大小是80x24)。
如果你有一個概念上簡單的函數,那么使用一個更長的函數是可以的,比如函數里是case。
在源文件中,用空行分隔函數。如果函數被導出,它的EXPORT*宏應該緊跟在結束的函數大括號行之后。例如:
int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
6. goto語句的使用
用不用goto一直是一個著名的爭議話題, Linux內核源代碼中對goto的應用非常廣泛,但是一般只限于錯誤處理中,其結構如:
if(register_a() != 0)
goto err;
if (register_b() != 0)
goto errl;
if(register_c() != 0)
goto err2;
if (register_d () != 0)
goto err3;
err3:
unregister_c();
err2:
unregister_b ();
errl:
unregister_a ();
err:
return ret;
這種將goto用于錯誤處理的用法實在是簡單而高效,只需保證在錯誤處理時注銷、資源釋放等,與正常的注冊、資源申請順序相反。
7. 注釋
Linux風格的注釋是c89 "/… /”風格。不要使用c99風格的“//…”注釋。
長(多行)注釋的首選樣式是:
/*
* 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.
*/
8.do {} while(0) 語句
在Linux內核中,經常會看到do {} while(0)這樣的語句。
許多人開始都會疑惑,認為do while(0)毫無意義,因為它只會執行一次,加不加do {} while(0)效果是完全一樣的,其實do {} while(0)的用法主要用于宏定義中。
這里用一個簡單的宏來演示:
#define SAFE_FREE (p) do{ free (p); p = NULL;} while (0)
假設這里去掉do...while(0),即定義SAFE_DELETE為:
#define SAFE FREE (p) free (p); p = NULL;
那么以下代碼:
if (NULL != p)
SAFE_DELETE(p)
else
.../* do something */
會被展開為:
if (NULL != P)
free (p); p = NULL;
else
.../* do something */
展開的代碼中存在兩個問題:
1)因為if分支后有兩個語句,導致else分支沒有對應的if,編譯失敗。
2)假設沒有else分支,則SAFE_FREE中的第二個語句無論if測試是否通過,都會執行。
的確,將SAFE_FREE的定義加上{}就可以解決上述問題了,即:
#define SAFE_FREE (p) { free (p); p= NULL; }
這樣,代碼:
if (NULL != p)
SAFE_DELETE(p)
else
... /* do something */
會被展開為:
if (NULL != p)
{ free (p); P = NULL; }
else
.../* do something */
但是,在C程序中,在每個語句后面加分號是一種約定俗成的習慣,那么,如下代碼:
if (NULL != p)
SAFE_DELETE (p);
else
.... /* do something */
將被擴展為:
if (NULL != p)
{ free (p); p = NULL; };
else
.../* do something */
這樣else分支就又沒有對應的if了,編譯將無法通過。
假設用了do {} while(0)語句,情況就不一樣了,同樣的代碼會被展開為:
if (NULL != p)
do{ free (p); p= NULL; } while (0);
else
.../* do something */
而不會再出現編譯問題。do{} while(0)的使用完全是為了保證宏定義的使用者能無編譯錯誤地使用宏,它不對其使用者做任何假設。
9. 其他規定
1.原則上不使用typedef,Linux認為typedef會使可讀寫變差
2.內聯函數通常不超過三行
評論
查看更多