建議0 不要讓main函數返回void
操作系統將main作為程序入口,main函數執行程序代碼,最後返回程序的退出狀態。但是C++中有一個好壞難定的規定:
在main函數中,return語句用於離開main函數(析構掉所有的具有動態生存時間的對象),並將其返回值作為參數來調用exit函數。如果函數執行到結尾而沒有遇到return語 句,其效果等同於執行了return 0;。
也就是說編譯器會協助完成返回值的問題。
然而,這樣的壞處就是,當編譯器不支持這個規定的時候,程序就會出錯,比如
int main()
{
}
在VC下編譯是成功的,在g++下編譯,就會提示錯誤:‘main’必須返回’int‘
建議1 區分0的4個面孔
1 整型0
2 空指針NULL
3 字符串結束標記''
' '是一個字符,占8位,其二進制位表示是 00000000,在C/C++中,''作為字符串的結束標記,是唯一的結束標記
4 邏輯FALSE/false
false/true是標准C++語言裡新增的關鍵字,而FALSE/TRUE是通過#define定義的宏:
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#defineTRUE 1
#endif
也就是說FALSE/TRUE是int類型,而false/true是bool型,兩者是不一樣的,bool在C++裡是占用1個字節
建議2 避免那些有運算符引起的混亂
=和== :在if語句中 比較兩個表達式是否相等,
if( nValue == 0)
{ ... }
如果程序員出現疲勞或精神不集中,把’==‘寫成’=‘,這樣if(nValue = 0),那麼這個if條件是恆成立,並且nValue被賦值為0,並且不會提示錯誤
這恐怕不是程序員想要的。。。
但如果把常量寫在前面,如if(0 == nValue){ },這樣如果程序員寫成if(0 = nValue){ },編譯器會直接的提示錯誤
但是對於&和&& 、|和|| 這類運算符,就需要平時養成謹慎的習慣了。
建議3 對表達式計算順序不要向當然
讓我們來看一個例子
if(nGrade & MASK == GRAND_ONE)
{...}
我們的本意是,通過nGrade和MASK取與,然後在比較是否等於GRAND_ONE,
可是,實際上上面的代碼的真實效果是if( nGrade & (MASK == GRAND_ONE)){}
這個建議的核心是,不要吝啬括號,讓語義表達的更准確,這樣可以減少出錯
如: a = p() + q() * r();
三個函數p() 、q() 、r()的執行順序可能是6種組合中的一個,所以a的值是不確定的,在這種情況下,就需要明確一種執行順序,
int x=p();
int y = q();
a = x+y*r();
類似的: expr1 ? expr2 : expr3
建議4 小心宏#define使用中的陷阱
定義宏時,要使用完備的括號:
比如定義兩個參數相加, #define ADD(a,b) ((a)+(b))是一個安全的方式
使用宏時,不允許參數發生變化,
定義宏時,用大括號將宏所定義的多條表達式括起來
建議5 不要忘記指針變量的初始化
局部變量的指針未初始化,可能導致程序崩潰
全局變量的指針,編譯器會悄悄完成變量的初始化(0)。
建議6 明晰逗號分隔表達式的奇怪之處
逗號表達式是從C繼承來的,其中每個表達式都會被執行,不過,整個表達式的值僅是最右邊表達式的結果
如:if(++x,--y,x<20 && y >0),該語句返回的是“ x<20 && y>0”與0比較的結果
另外,逗號表達式既可以用作左值,也可以用作右值。
建議7 時刻提防內存溢出
C語言中的字符串庫沒有響應的安全保護措施,strcpy、strcat等函數操作時沒有檢查緩沖區大小,容易引起安全問題
好的方法是,定義一個函數,並傳遞確定的長度,如:
const int DATA_LENGTH = 16;
void DataCopy(char* src ,int len)
{
char dst[DATA_LENGTH];
for(int i=0;src[i] != 0 && i
cout<
if(len < DATA_LENGTH)
strcpy(dst,src);
}
這裡如果,src的長度是10,當i=10時,src[10]就已經越界了。。。
建議8 拒絕晦澀難懂的函數指針
比如 void (*p[10]) (void (*)() );
1 聲明一個無參數、返回空的函數指針的typedef,如:typedef void (*pfv)();
2 聲明一個指向參數為pfv且返回空的函數指針, 如 : typedef void (*pFun_taking_pfv) (pfv));
3 定義數組,pFun_taking_pfv p[10];
建議9 防止頭文件重發包含
方式一:
#ifndef __TEST_H__
#define __TEST_H__
......
#endif
方式二:
#pragma once
優缺點:方式一的缺點是宏導致的編譯時間長
方式二的缺點是只是針對物理路徑相同的文件,而不是文件的內容