《C編程習慣》讀書筆記(1-6章)

最近在看兩本國人寫的書:C編程習慣、Linux C編程。越看越發現如獲至寶。有時真覺得,看國外的書,都能將晦澀概念深入淺出解釋通透,而國內的書,能切合國人的習慣來解釋和應用知識。以前只青睞國外的書,這兩本國內的電子書本來只想簡單瀏覽一遍鞏固基礎,現在越看越想做讀書筆記,因爲實在是很多看似簡單但實用的小技巧。鑑於C編程習慣只有100頁,那就先小後大吧。

 

開頭先感謝《C編程習慣》作者林銳的創作與開源。

頭文件

1.爲了防止頭文件被重複引用,應當用 ifndef/define/endif結構產生預

處理塊。

2. #include <filename.h>格式來引用標準庫的頭文件(編譯器將

從標準庫目錄開始搜索)。

3. #includefilename.h格式來引用非標準庫的頭文件(編譯器將

從用戶的工作目錄開始搜索)。

 

 

命名規則

 

共性規則

本節論述的共性規則是被大多數程序員採納的,我們應當在遵循這些共性規則的前
提下,再擴充特定的規則。


    1.標識符應當直觀且可以拼讀,可望文知意,不必進行“解碼”。


    標識符最好採用英文單詞或其組合,便於記憶和閱讀。切忌使用漢語拼音來命名。程序中的英文單詞一般不會太複雜,用詞應當準確。例如不要把CurrentValue寫成NowValue

 

2.標識符的長度應當符合“ min-length&& max-information”原則。


    幾十年前老 ANSI C 規定名字不準超過6個字符,現今的 C++/C 不再有此限制。一般來說,長名字能更好地表達含義,所以函數名、變量名、類名長達十幾個字符不足爲怪。名字也不是越長越好! 例如變量名 maxval 就比maxValueUntilOverflow好用。單字符的名字也是有用的,常見的如 i,j,k,m,n,x,y,z 等,它們通常可用作函數內的局部變量。

 

3.命名規則儘量與所採用的操作系統或開發工具的風格保持一致。


Windows應用程序的標識符通常採用“大小寫”混排的方式,如AddChild

Unix 應用程序的標識符通常採用“小寫加下劃線”的方式,如add_child

 

4.程序中不要出現僅靠大小寫區分的相似的標識符。
例如:
int x, X; // 變量xX容易混淆
void foo(int x); // 函數fooFOO容易混淆
void FOO(float x);


5.程序中不要出現標識符完全相同的局部變量和全局變量,儘管兩者的作用域不同而不會發生語法錯誤,但會使人誤解。


6.變量的名字應當使用“名詞”或者“形容詞+名詞”。
例如:
float value;
float oldValue;
float newValue;


7.全局函數的名字應當使用“動詞”或者“動詞+名詞”(動賓詞組)。類的成員函數應當只使用“動詞”,被省略掉的名詞就是對象本身。

例如:
DrawBox(); // 全局函數
box->Draw(); // 類的成員函數


8.用正確的反義詞組命名具有互斥意義的變量或相反動作的函數等。
例如:
int minValue;
int maxValue;
int SetValue(…);
int GetValue(…);


9.儘量避免名字中出現數字編號,如Value1,Value2等,除非邏輯上的確需要編號。這是爲了防止程序員偷懶,不肯爲命名動腦筋而導致產生無意義的名字(因爲用數字編號最省事)。

 

 個人比較認同的命名規則

 

1. 類名和函數名用大寫字母開頭的單詞組合而成。
例如:
class Node; // 類名
class LeafNode; // 類名
void Draw(void); // 函數名
void SetValue(int value);// 函數名

 

2.      變量和參數用小寫字母開頭的單詞組合而成。
例如:
BOOL flag;
int drawMode;

3.      常量全用大寫的字母,用下劃線分割單詞。
例如:
const int MAX = 100;
const int MAX_LENGTH = 100;

4.      靜態變量加前綴s_(表示static)。
例如:
void Init(…)
{
static int s_initValue; //
靜態變量

}

5.      如果不得已需要全局變量,則使全局變量加前綴g_(表示global)。
例如:
int g_howManyPeople; // 全局變量
int g_howMuchMoney; // 全局變量

6.      類的數據成員加前綴m_(表示member),這樣可以避免數據成員與
成員函數的參數同名。
例如:
void Object::SetValue(int width, int height)
{
m_width = width;
m_height = height;
}


7.      爲了防止某一軟件庫中的一些標識符和其它軟件庫中的衝突,可以爲各種標識符加上能反映軟件性質的前綴。例如三維圖形標準OpenGL的所有庫函數均以gl開頭,所有常量(或宏定義)均以GL開頭。

 

if 語句

BOOL flag 與“零值”比較

if ( flag )
if ( !flag )


float x 與“零值”比較

const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
不可將浮點變量用“ ==或“=與數字比較,應該設法轉化“>=或“<=此類形式。


char *p 與“零值”比較

if (p == NULL)
if (p != NULL)


if/else/return 的組合

return (condition ? x : y);

 

循環語句

在多重循環中,如果有可能,應當將最長的循環放在最內層,最短的
循環放在最外層,以減少 CPU跨切循環層的次數。

 

for 語句的循環控制變量的取值採用“半開半閉區間”寫法。

for (int x=0; x<N; x++)
{

}


const #define的比較
C++ 語言可以用 const 來定義常量,也可以用 #define 來定義常量。但是前者比後
者有更多的優點:


1const常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安
全檢查。而對後者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會
產生意料不到的錯誤(邊際效應)。


2) 有些集成化的調試工具可以對const常量進行調試,但是不能對宏常量進行調
試。

 

需要對外公開的常量放在頭文件中,不需要對外公開的常量放在定義文件的頭部。爲便於管理,可以把不同模塊的常量集中存放在一個公共的頭文件中。

 

 

函數設計s

 

參數的規則
1.參數的書寫要完整,不要貪圖省事只寫參數的類型而省略參數名字。如果函數沒有參數,則用void填充。
例如:
void SetValue(int width, int height); // 良好的風格
void SetValue(int, int); // 不良的風格
float GetValue(void); // 良好的風格
float GetValue(); // 不良的風格


2.參數命名要恰當,順序要合理。


例如編寫字符串拷貝函數 StringCopy,它有兩個參數。如果把參數名字起爲str1
str2,例如
void StringCopy(char *str1, char *str2);


那麼我們很難搞清楚究竟是把 str1拷貝到str2中,還是剛好倒過來。可以把參數名字起得更有意義,如叫strSourcestrDestination。這樣從名字上就可以看出應該把strSource拷貝到strDestination。這兩個參數那一個該在前那一個該在後?參數的順序要遵循程序員的習慣。一般地,應將目的參數放在前面,源參數放在後面。

 

3.如果函數返回值是一個對象,要考慮return語句的效率。例如
return String(s1 + s2);


這是臨時對象的語法,表示“創建一個臨時對象並返回它”。不要以爲它與“先創建
一個局部對象 temp並返回它的結果”是等價的,如
String temp(s1 + s2);
return temp;


實質不然,上述代碼將發生三件事。首先,temp對象被創建,同時完成初始化;然
後拷貝構造函數把 temp拷貝到保存返回值的外部存儲單元中;最後,temp在函數結束時被銷燬(調用析構函數)。然而“創建一個臨時對象並返回它”的過程是不同的,編譯器直接把臨時對象創建並初始化在外部存儲單元中,省去了拷貝和析構的化費,提高了效率。類似地,我們不要將
return int(x + y); // 創建一個臨時變量並返回它
寫成
int temp = x + y;
return temp;


由於內部數據類型如 int,float,double的變量不存在構造函數與析構函數,雖然該 “
時變量的語法”不會提高多少效率,但是程序更加簡潔易讀。

 

 

面試時編寫一個簡單的函數,一般從三個方面考查:

1)編程風格;

2)出錯處理;

3)算法複雜度分析。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章