最近看到一個關於編程語言的調查,我發現到目前為止,C 編程語言在全球開發者中仍然穩居前三,如下圖所示。
前20名榜單排行榜:

如此多的代碼使用C來編寫,我想分享我多年學習總結的一些好的C語言編程實踐:
一、不要使用gets()和strcpy()
再也不要使用諸如gets()、strcpy()、sprintf()等等這些函數,這已經是一個廣為人知的一個事實(好吧,緩沖區溢出大家都知道吧),但這些函數仍然在庫中,以用來支持那些已經使用這些函數的代碼。如果你使用man手冊關於gets()的說明,會發現:
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
當你使用這些函數時,甚至一些編譯器如gcc 都會給你警告,gcc 給出類似下面的警告:
warning: the `gets’ function is dangerous and should not be used.
足見整個開發環境已經意識到這個問題,所以我們應該重視起來,使用像fgets()、strncpy()、snprinf()等這些函數,它們更好地根據緩沖區的大小來控制輸入。
二、函數只能有一個返回點
在一個函數中隨意地使用return語句,這是一個很不好的編程習慣,函數有多個返回點會增加代碼管理的復雜度。通常一個代碼由多個開發者完成就可以出現這個問題,但即使如此,任何人在開發的過程中都會造成這個問題。記住僅有一個返回點是好的編程習慣。
舉例來說:
#include<stdio.h> ... ... int main(void) { ... ... ... if(/*some condition*/) return 1; // Not a good programming practice else if(/*some condition*/) return 2; // Not a good programming practice else return -1; // Not a good programming practice }
更好的代碼應該這樣寫:
#include<stdio.h> ... ... int main(void) { int ret = 0; ... ... ... if(/*some condition*/) ret = 1; else if(/*some condition*/) ret = 2; else ret = -1; return ret; }
三、適當的地方進行基本的優化
有時當我們寫一個邏輯時,我們會忽略事情是如何通過這個邏輯完成的。我的意思是,我們應該在適當的地方進行一些基本的優化。
看下面的一段代碼:
... ... int len = 0; char *buff = "Linux"; while(/*Some condition*/) { ... ... // updating 'len' here ... if(len > strlen(buff)) { //Do some stuff here } ... ... ... } ... ... ...
看看上面的代碼,函數strlen()在循環中一次又一次地計算buff指向的字符串的長度,這是沒經過優化的代碼,因為buff指向的緩沖區在 while循環中始終沒有改變,因此長度也不會改變。更好的做法是,在while循環之前調用一次strlen()函數,用一個變量來保存buff的長 度,在循環中使用這個變量就可以了。像下面這種做法:
... ... ... int len = 0; int buff_len = 0; char *buff = "Linux"; buff_len = strlen(buff); while(/*Some condition*/) { ... ... // updating 'len' here ... if(len > buff_len) { //Do some stuff here } ... ... ... } ... ... ...
這種做法保證了你的代碼在適當的地方進行了基本的優化,在大數據量的情況下,會省不少時間。
四、總是使用相應的庫調用函數
假設你想在Linux下通過C語言打開一個文件,有兩個函數可用——fopen()和open()。fopen()是一個庫函數調用,而open()是一個系統調用,你會選擇哪個函數呢?
如果你選擇的是open()系統調用,那么我必須說如果在相應的庫函數存在的情況下,選擇一個系統調用不是一個好的編程實踐。這是因為:
- 系統調用與系統相關的。舉例來說,在Linux系統下寫的代碼不能確保也能運行在非Linux系統下。然而,帶有C庫的系統都有相應的庫函數,這兒的問題是移植性的問題。
- 其次,系統調用與庫函數比較起來相對來說更耗時。
所以,確保任何地方可用均使用庫調用。
五、用宏替代常量
假設你需要寫成千上萬行代碼,涉及到上百個文件,你在整個文件和代碼中用到一個固定值,比如說1024。現在突然你意識到要將這個值改成2048, 你將怎么做?你要確定所有使用這個值的位置,並手動將值改成2048;或者,在你的IDE中使用“查找”命令,然后試圖用2048來替換1024。
然而,這兩種方法都不是很好的,更好的編程實踐是在頭文件中使用C語言宏定義這個值,在其它需要使用這個值的地方用宏來代替,這樣,如果需要改變這個值的時候,只需要改變一個地方即可。同時,給宏取一個有關聯的名字,可以使這個值用來做什么變得非常清晰。
編譯自:5 good C programming practices from http://mylinuxbook.com/5-good-c-programming-practices/