第六章:函數
函數應該簡短而漂亮,并且只完成一件事情。函數應該可以一屏或者兩屏顯示完(我們都知道ISO/ANSI屏幕大小是80x24),只做一件事情,而且把它做好。
一個函數的最大長度是和該函數的復雜度和縮進級數成反比的。所以,如果你有一個理論上很簡單的只有一個很長(但是簡單)的case語句的函數,而且你需要在每個case里做很多很小的事情,這樣的函數盡管很長,但也是可以的。
不過,如果你有一個復雜的函數,而且你懷疑一個天分不是很高的高中一年級學生可能甚至搞不清楚這個函數的目的,你應該更嚴格的遵守最大限制。使用輔助函數,并為之取個具描述性的名字(如果你覺得其對性能要求嚴格的話,你可以要求編譯器將它們內聯展開,它往往會比你更好的完成任務。)
函數的另外一個衡量標準是本地變量的數量。此數量不應超過5-10個,否則你的函數就有問題了。重新考慮一下你的函數,把它分拆成更小的函數。人的大腦一般可以輕松的同時跟蹤7個不同的事物,如果再增多的話,就會糊涂了。即便你聰穎過人,你也可能會記不清你2個星期前做過的事情。
在源文件里,使用空行隔開不同的函數。如果該函數需要被導出,它的EXPORT*宏應該緊貼在它的結束大括號之下。比如:
int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
在函數原型中,包含函數名和它們的數據類型。雖然C語言里沒有這樣的要求,在Linux里這是提倡的做法,因為這樣可以很簡單的給讀者提供更多的有價值的信息。
第七章:集中的函數退出途徑
雖然被某些人聲稱已經過時,但是goto語句的等價物還是經常被編譯器所使用,具體形式是無條件跳轉指令。當一個函數從多個位置退出并且需要做一些通用的清潔工作的時候,goto的好處就顯現出來了。
理由是:
- 無條件語句容易理解和跟蹤
- 嵌套程度減小
- 可以避免由于修改時忘記更新某個單獨的退出點而導致的錯誤
- 減輕了編譯器的工作,無需刪除冗余代碼;)
int fun(int a)
{
int result = 0;
char *buffer = kmalloc(SIZE);
if (buffer == NULL)
return -ENOMEM;
if (condition1) {
while (loop1) {
...
}
result = 1;
goto out;
}
...
out:
kfree(buffer);
return result;
}