編程常見bug檢查1

總結(jié)一些日常工作常見的代碼和編程情況昔驱,會分幾個文章寫出疹尾,也許對一些朋友有些作用

一、基礎(chǔ)風(fēng)格

1舍悯、設(shè)計函數(shù)參數(shù)時航棱,請注意函數(shù)參數(shù)的順序和個數(shù)

????*一般而言,建議輸入?yún)?shù)在前萌衬,輸出參數(shù)在后

????*輸入?yún)?shù)是指針饮醇,且不改變時,請注意定義的時候類型加const

????*輸入?yún)?shù)是struct或者Class實(shí)例且不修改時秕豫,可以使用const&來傳遞朴艰,或者const指針

????????**這樣可以避免當(dāng)傳入形參的實(shí)例對象較大時观蓄,拷貝會降低效率

????????**還可以避免對該對象的改變

????*盡可能的減少不必要的參數(shù)個數(shù)

2、避免不必要的函數(shù)調(diào)用

????*不合理的代碼:

????char* pszString = “hello祠墅, it's me”;

????for(int i = 0;i < strlen(pszString); ++i)

????{

????????侮穿。。毁嗦。DoSomething

????}

????*合理的代碼

????char* pszString = “hello亲茅, it's me”;

????int nLength = (int)strlen(pszString);

????for(int i = 0;i < nLength; ++i)

????{

????????。狗准。克锣。DoSomething

????}

3、避免頭文件定義全局變量腔长,防止重復(fù)引用頭文件時袭祟,全局變量被重復(fù)定義;

4捞附、字符串拼接時請注意避免越界

????1)因?yàn)橛袝r候文件存儲的文件名字段可能是錯的巾乳,避免異常情況下的越界,拼接時需要注意是否越界

????2)snprintfs的count參數(shù)請用_TRUNCATE鸟召,避免buffer太小導(dǎo)致的宕機(jī)(針對windows的PC)

????https://msdn.microsoft.com/en-us/library/ms175769.aspx

5胆绊、如果處理資源出錯,需要寫日志時药版,請寫明出錯的文件名

6辑舷、繼承接口或抽象類的子類,析構(gòu)函數(shù)請注意定義為virtual

????*當(dāng)指針類型是父類指針槽片,指向的內(nèi)容是子類對象時,定義為virtual可以避免delete該指針時會出現(xiàn)泄露的情況

7肢础、DWORD/long和void*轉(zhuǎn)換

????*64位的程序下还栓,void*是8字節(jié),DWORD/long是4字節(jié)传轰。這樣如果是指針存儲在DWORD剩盒,高位的4個字節(jié)是會丟失

8、推薦調(diào)用函數(shù)時慨蛙,對返回值進(jìn)行判斷辽聊,同時對錯誤的返回值做相應(yīng)的錯誤處理

????*確認(rèn)是否需要函數(shù)返回值?

????*確認(rèn)出錯了怎么辦期贫?錯誤如何表達(dá)跟匆?

????*是否需要定義出錯處理的準(zhǔn)則或出錯后是否需要還原?

二通砍、斷言的使用

1玛臂、static_assert執(zhí)行編譯時的斷言檢查

????如:static_assert(sizeof(char *) == 8, "不是64位模式")

2烤蜕、斷言來檢查參數(shù)合法性的場景:

????1)代碼執(zhí)行之前或者在函數(shù)入口處,用斷言來檢查參數(shù)的合法性

????2)代碼執(zhí)行之后或在函數(shù)出口處迹冤,用斷言來檢查是否正確執(zhí)行讽营,輸出或內(nèi)部狀態(tài)是否如預(yù)期

3、避免用斷言去檢查程序錯誤:

????1)外部不可靠的數(shù)據(jù)泡徙,應(yīng)該做嚴(yán)格檢查才能放到系統(tǒng)內(nèi)部橱鹏,這個時候它是守衛(wèi),提前檢驗(yàn)和過濾不合理的數(shù)據(jù)和參數(shù)堪藐,應(yīng)該使用錯誤檢查處理代碼莉兰,而不是用斷言來做檢查

????????*外部不可靠的數(shù)據(jù):如不合理的用戶輸入、或其他模塊傳入到該模塊的消息或數(shù)據(jù)庶橱,

????????有點(diǎn)像是對項(xiàng)目組外的員工贮勃,要動用項(xiàng)目組的資源,是需要經(jīng)過審核的

????2)系統(tǒng)內(nèi)部的交互數(shù)據(jù)(如程序內(nèi)部的調(diào)用)苏章,可以用斷言來檢查意想不到的錯誤寂嘉,或者程序內(nèi)部的假設(shè)。(其實(shí)就是檢查它的潛規(guī)則和邏輯邊界枫绅、隱形假定)

????????*因?yàn)橄到y(tǒng)內(nèi)的調(diào)用者一般情況下是有義務(wù)負(fù)責(zé)傳遞給自己內(nèi)部的數(shù)據(jù)是合理正常的數(shù)據(jù)

????????就像項(xiàng)目內(nèi)的員工泉孩,對于使用項(xiàng)目組的資源的門檻就會低很多

????????*可理解為assert和出錯處理是對所寫程序建立不同的信用級別,也方便在Release版可以性能更好的運(yùn)行程序

????3)推薦針對public的函數(shù)或接口的入口處對參數(shù)做嚴(yán)格的錯誤檢查并淋;對于Private的函數(shù)或者只有這個模塊能看到的寓搬,可以用assert

4、避免斷言中使用改變環(huán)境的語句:

????如不正確的代碼:

????int Test(int i)

????{

????????assert(i++); ?//debug版和release版的i值就會不一樣

????????return i;

????}

????int main()

????{

????????int i = 1;

????????int nValue = Test(i);

????????printf("%d\n", ?nValue);

????????return 0;

????}

????合理的形式:

????int Test(int i)

????{

????????assert(i);

????????return ++i;

????}

????注:與改變環(huán)境的語句類似的行為是宏定義县耽。

????*請盡量不要在assert中調(diào)用宏句喷,以防止宏的副作用

5、防錯性程序設(shè)計常常要解決的是:現(xiàn)實(shí)中兔毙,防止用戶數(shù)據(jù)丟失或程序崩潰而采取的措施唾琼。只是除此之外:

????*我們是否還希望進(jìn)行防錯性程序設(shè)計時,錯誤不要被隱瞞澎剥?

????*實(shí)現(xiàn)程序時锡溯,我們想要什么?我們期待錯誤發(fā)生時哑姚,我們能得到什么或者怎樣處理它祭饭?

????????**這有點(diǎn)像我們接到一個任務(wù)的思考點(diǎn):

????????1)我們做這個事的目標(biāo)是完成它?做好它叙量?

????????2)做這個事是希望減輕自己負(fù)擔(dān)倡蝙?減輕別人負(fù)擔(dān)?or both宛乃?

????????3)出問題時怎么辦悠咱?有預(yù)案嗎蒸辆?有線索嗎?系統(tǒng)里需要埋下什么報警方案析既?影響大嗎躬贡?

三、內(nèi)存

1眼坏、內(nèi)存常見的設(shè)計問題導(dǎo)致的代碼bug

????1)內(nèi)存的分配拂玻、釋放接口應(yīng)配對;且應(yīng)該限定在一個同一模塊或者同一抽象層內(nèi)進(jìn)行

????????*否則會加大程序猿追蹤內(nèi)存塊的生命周期的負(fù)擔(dān)

????????*還可能導(dǎo)致內(nèi)存泄露宰译、重復(fù)釋放該內(nèi)存檐蚜、非法訪問已經(jīng)釋放的內(nèi)存、寫入已經(jīng)釋放或者沒有分配的內(nèi)存等問題

????例:

????**不正確的代碼:

????#define MIN_MEM_SIZE 10

????int CompareMemorySize(char* pchBuffer, size_t uSize)

????{

????????if(uSize < MIN_MEM_SIZE)

????????{

????????????free(p);

????????????p = NULL;

????????????return -1;

????????}

????????return 0;

????}

????void AllocMemory(size_t uSize)

????{

????char *pchBuffer = (char*)malloc(uSize);

????if(pchBuffer == NULL)

????{.........}

????if(CompareMemorySize(pchBuffer, uSize) == -1) ?//這里pchBuffer實(shí)際上是已經(jīng)釋放了

????{

????????free(pchBuffer);//重復(fù)釋放了pchBuffer

????????pchBuffer = NULL;

????????return;

` ? }

????........

????free(pchBuffer);

????pchBuffer = NULL;

}

**正確的代碼:

#define MIN_MEM_SIZE 10

int CompareMemorySize(char* pchBuffer, size_t uSize)

{

????if(uSize < MIN_MEM_SIZE)

????{

????????return -1;

????}

????return 0;

}

void AllocMemory(size_t uSize)

{

????char *pchBuffer = (char*)malloc(uSize);

????if(pchBuffer == NULL)

????{.........}

????if(CompareMemorySize(pchBuffer, uSize) == -1)

????{

????????free(pchBuffer);

????????pchBuffer = NULL;

????????return;

` }

????????........

????free(pchBuffer);

????pchBuffer = NULL;

}

????**這里可以總結(jié)出的維度:

(1)內(nèi)存的分配沿侈、釋放接口應(yīng)配對闯第;且應(yīng)該限定在一個同一模塊或者同一抽象層內(nèi)進(jìn)行

(2)盡可能函數(shù)的副作用越少越好:減少用戶記住調(diào)用函數(shù)時,需要了解過多的函數(shù)內(nèi)部的實(shí)現(xiàn)

2缀拭、避免對結(jié)構(gòu)體執(zhí)行逐個字節(jié)的比較

如:

typedef struct

{

char chValue;

int nCount;

char szBuffer[10];

}Buffer;

*不合理的代碼:

bool IsEqual(const Buffer *pBuffer1, const Buffer *pBuffer2)

?{

????//因?yàn)槟J(rèn)情況想存在字節(jié)對齊咳短,對齊的字節(jié)內(nèi)存里填充什么內(nèi)容和編譯器有關(guān)系,它的行為未定義蛛淋,所以這樣比較是錯的

????if(!memcmp(pBuffer1, pBuffer2, sizeof(Buffer)))

????????return true;

????return false;

}

*合理的代碼:

bool IsEqual(const Buffer *pBuffer1, const Buffer *pBuffer2)

{

????if(

????????pBuffer1->chValue == pBuffer2->chValue &&

????????pBuffer1->nCount == pBuffer2->nCount &&

` ? ? strcmp(pBuffer1->szBuffer, pBuffer2->szBuffer) == 0

????)

????????return true;

????return false;

}

3咙好、避免執(zhí)行零長度的內(nèi)存分配

????*C99規(guī)定,程序試圖調(diào)用malloc褐荷、calloc與realloc等系列內(nèi)存分配函數(shù)分配大小為0的內(nèi)存勾效,其行為時有具體編譯器所定義(可能返回NULL,可能返回長度為非零的值等)叛甫,從而導(dǎo)致產(chǎn)生未定義的行為

4层宫、內(nèi)存常見檢測問題:

????1)確保沒有訪問空指針

????2)分配和釋放內(nèi)存的操作是否配對

????3)出錯處理時,內(nèi)存是否有出現(xiàn)重復(fù)釋放其监、漏釋放卒密、或者釋放錯誤

????4)在指針賦值前,是否存在有內(nèi)存數(shù)據(jù)丟失

????5)當(dāng)釋放數(shù)組元素或者struct類型的元素時棠赛,都應(yīng)先遍歷子元素進(jìn)行釋放,再遍歷回父節(jié)點(diǎn)

????*注:如果class或者一些設(shè)計不好的接口膛腐,沒有注意提供配對的內(nèi)存操作接口時睛约,會導(dǎo)致各種隱患,如:內(nèi)存泄漏哲身、野指針等辩涝,需要另外檢查

????6)注意對函數(shù)返回值是動態(tài)分配內(nèi)存的檢查和內(nèi)部狀態(tài)的檢查

????7)引用計數(shù)的檢查

????8)內(nèi)存填充是否越界、或數(shù)據(jù)類型不正確

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勘天,一起剝皮案震驚了整個濱河市怔揩,隨后出現(xiàn)的幾起案子捉邢,更是在濱河造成了極大的恐慌,老刑警劉巖商膊,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伏伐,死亡現(xiàn)場離奇詭異,居然都是意外死亡晕拆,警方通過查閱死者的電腦和手機(jī)藐翎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來实幕,“玉大人吝镣,你說我怎么就攤上這事±ケ樱” “怎么了末贾?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長整吆。 經(jīng)常有香客問我拱撵,道長,這世上最難降的妖魔是什么掂为? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任裕膀,我火速辦了婚禮,結(jié)果婚禮上勇哗,老公的妹妹穿的比我還像新娘昼扛。我一直安慰自己,他們只是感情好欲诺,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布抄谐。 她就那樣靜靜地躺著,像睡著了一般扰法。 火紅的嫁衣襯著肌膚如雪蛹含。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天塞颁,我揣著相機(jī)與錄音浦箱,去河邊找鬼。 笑死祠锣,一個胖子當(dāng)著我的面吹牛酷窥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伴网,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼蓬推,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了澡腾?” 一聲冷哼從身側(cè)響起沸伏,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤糕珊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后毅糟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體红选,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年留特,在試婚紗的時候發(fā)現(xiàn)自己被綠了纠脾。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜕青,死狀恐怖苟蹈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情右核,我是刑警寧澤慧脱,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站贺喝,受9級特大地震影響菱鸥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜躏鱼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一氮采、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧染苛,春花似錦鹊漠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至畔师,卻和暖如春娶靡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背看锉。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工姿锭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伯铣。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓艾凯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親懂傀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 題目類型 a.C++與C差異(1-18) 1.C和C++中struct有什么區(qū)別蜡感? C沒有Protection行為...
    阿面a閱讀 7,635評論 0 10
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法蹬蚁,類相關(guān)的語法恃泪,內(nèi)部類的語法,繼承相關(guān)的語法犀斋,異常的語法贝乎,線程的語...
    子非魚_t_閱讀 31,587評論 18 399
  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,284評論 0 6
  • 1 文件結(jié)構(gòu) 每個C++/C程序通常分為兩個文件叽粹。一個文件用于保存程序的聲明(declaration)览效,稱為頭文件...
    Mr希靈閱讀 2,863評論 0 13
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)虫几,斷路器锤灿,智...
    卡卡羅2017閱讀 134,601評論 18 139