軟件代碼評審檢查點(diǎn)--C-C++.doc_第1頁
軟件代碼評審檢查點(diǎn)--C-C++.doc_第2頁
軟件代碼評審檢查點(diǎn)--C-C++.doc_第3頁
軟件代碼評審檢查點(diǎn)--C-C++.doc_第4頁
軟件代碼評審檢查點(diǎn)--C-C++.doc_第5頁
已閱讀5頁,還剩17頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

軟件代碼評審檢查點(diǎn)-C-C+文件結(jié)構(gòu)審查【檢查點(diǎn)1 】文件名是否和實(shí)際內(nèi)容相符?規(guī)范性說明文件名應(yīng)該清晰說明出該文件的功能和作用。案例略【檢查點(diǎn)2 】多個(gè)模塊公用的定義和函數(shù)原型的說明是否放在“*.h”?說明一般來說,*.h文件是公用的頭文件,文件中申明的宏、結(jié)構(gòu)、函數(shù)原型等,一其他的模塊需要引用。案例略【檢查點(diǎn)3 】私有的申明和函數(shù)原型的說明是否放在“*.inc”?說明一般來說,*.inc文件是私有的頭文件。文件中申明的宏、結(jié)構(gòu)、函數(shù)原型等,是僅供本模塊使用。案例略【檢查點(diǎn)4 】頭文件是否使用了#ifndef-#endif宏開關(guān)來防止重復(fù)引用?說明一般來說,頭文件通過如下方法避免重復(fù)引用:#ifndef _XXX_H_#define _XXX_H_/*文件主體*/#endif 【檢查點(diǎn)5 】函數(shù)原型是否沒有明確申明返回值類型說明雖然C語言并不需要精確定義和聲明函數(shù)返回類型,如果函數(shù)沒有返回值,則定義為類型void。如果函數(shù)沒有定義返回類型,編譯器將認(rèn)為其返回類型為int。在這種情況,很難判斷函數(shù)是否應(yīng)該有返回值。為了避免這種情況,函數(shù)返回類型應(yīng)該被定義和聲明。案例錯(cuò)誤書寫:SSfunction() ;正確書寫:void SSfunction() ;預(yù)處理【檢查點(diǎn)1 】宏定義是否缺少了“( )”符號?說明對于表達(dá)式的宏定義,注意要對變量和表達(dá)式本身使用“( )”,防止宏展開時(shí)出錯(cuò)。案例案例一注意下面的宏定義極易出現(xiàn)問題: #define ADD(x, y) x + y上面的宏在如下代碼中出錯(cuò): c = ADD(a, b) /2;宏展開后的形式為: c = a + b /2;而不是: c = (a + b) /2;案例二 #define MULTI(x, y) x*y在程序中代碼如下: a = MULTI( b+c, 2);宏展開后為: a = b + c * 2 ;而不是: a = (b + c) * 2;【檢查點(diǎn)2 】宏定義是否存在不期望或者意料之外的附加效應(yīng)?說明宏是一個(gè)短行的文本,或者說文本模板,它可以被擴(kuò)充為更長的文本.通常由宏產(chǎn)生的問題并不在宏定義本身,而往往由其下面的程序引起. 采用宏可以使代碼簡化,但它也可能隱藏重要的細(xì)節(jié)和關(guān)鍵的操作.案例 #define SQUARE ( x ) ( ( x ) * ( x ) ) . . . w = SQUARE ( + value ); 實(shí)際對宏SQUARE的引用將導(dǎo)致value被增加兩次 , 因?yàn)檫@個(gè)語句將被C預(yù)處理器擴(kuò)充以下形式: w = ( ( + + value ) * ( + + value ) );【檢查點(diǎn)3 】是否存在通過定義宏來改變程序控制流程?說明通過定義宏來改變程序控制流程實(shí)際上是很糟糕的編程技巧案例 錯(cuò)誤形式: #define FOR_ALL for ( i = 0; i cmd.req.req2, tmrc ) );正確形式: return ( & MLtisfail ( mltmsg - cmd.req.req2, tmrc ) );在如下這些情況下傳送指針作為參數(shù)是更好的選擇: - 需要傳送大量的數(shù)據(jù)和大型的數(shù)據(jù)結(jié)構(gòu)作為輸入時(shí), - 被調(diào)函數(shù)需要修改調(diào)用函數(shù)的數(shù)據(jù)時(shí).【檢查點(diǎn)4 】返回值的所攜帶的信息是否的確是調(diào)用函數(shù)所需要的? 說明略【檢查點(diǎn)5 】函數(shù)入?yún)⑹情g接引用參數(shù)時(shí)候,當(dāng)中是否漏掉一個(gè)層次? 說明 案例 錯(cuò)誤形式: DXal_fndnxt ( . . . , ( DXALMDATA * ) & data_ptr );正確形式: DXal_fndnxt ( . . . , ( DXALMDATA * * ) & data_ptr );【檢查點(diǎn)6 】函數(shù)退出時(shí)是否有正確的返回值?說明看到函數(shù)調(diào)用,要養(yǎng)成習(xí)慣,進(jìn)入函數(shù)內(nèi)部瞄一眼。看看函數(shù)的正常值和異常值都是什么??纯捶祷刂敌璨恍枰袛???纯从袥]有參數(shù)理解不一致的地方。案例錯(cuò)誤形式:if ( VOS_strnicmp(szFullName, DEV_ATM_NAME , DEV_ATM_NAMELEN) = 0 ) ulIfType = DEV_GetIfTypeFromIfName( szFullName );if ( ulIfType = -1 )EXEC_OutString( ulExecID, rnUnknown interface type );return VOS_ERR;/*得到端口的索引*/ulRet = DEV_GetIfIndexFromIfName( szFullName, &ulIfIndex);if (SUCCESS != ulRet)EXEC_OutString( ulExecID, rnUnknown interface number );return VOS_ERR;/*判斷端口是否已經(jīng)存在*/ pIfIns = DEV_GetIfFromIndex(ulIfIndex);if(NULL = pIfIns) rc = DEV_Cnsl_CreateIf(ulExecID, ulIfType, ulIfIndex, ulSubType); if(SUCCESS != rc) return SUCCESS; pIfIns = DEV_GetIfFromIndex(ulIfIndex); if(NULL = pIfIns) COUT_OUTPUT_DIAG(MOD_DEV, COUT_LEVEL_WARNING, pIfIns = NULL is invalid %s.%d, _FILE_, _LINE_); return DEV_ERR_GEN; 函數(shù)使用-1作為非法值,而在DEV_GetIfTypeFromIfName函數(shù)中:U32 DEV_GetIfTypeFromIfName(CHAR *ifName)CHAR szIfType20; /接口的類型字符串U32ulIfType;U32 strLen;U32 i;if(NULL =ifName)COUT_OUTPUT_DIAG(MOD_DEV, COUT_LEVEL_WARNING, ifName = NULL in GetIfTypeFromIfName %s.%d, _FILE_, _LINE_); return DEV_ERR_VALUE; strLen = VOS_strlen(ifName); if(0 = strLen) /*字符串為空,返回錯(cuò)誤*/COUT_OUTPUT_DIAG(MOD_DEV, COUT_LEVEL_WARNING, strlen = 0 %s.%d, _FILE_, _LINE_); return DEV_ERR_VALUE; VOS_Mem_Set(szIfType, 0, sizeof(szIfType); /*-*/ /*從字符串的尾部向前查找,直到找到第一個(gè)不是數(shù)字的字符 */ /*-*/ for(i = strLen-1; i = 0; i-) /*字符不等于., /或數(shù)字字符時(shí)循環(huán)結(jié)束*/ if(ifNamei != . & ifNamei != / & (ifNamei 9) break; VOS_strncpy(szIfType, ifName, i+1);ulIfType = DEV_IfStringToType( szIfType );return ulIfType;函數(shù)的一個(gè)錯(cuò)誤返回值是DEV_ERR_VALUE,很顯然,兩邊參數(shù)理解不一致。【檢查點(diǎn)7 】調(diào)用其他函數(shù)時(shí)是否對返回值進(jìn)行了判斷?說明略【檢查點(diǎn)8 】在函數(shù)調(diào)用前是否認(rèn)真核實(shí)傳參的數(shù)據(jù)類型? 說明 案例 錯(cuò)誤形式: (void) CCbinasc ( loop_ptr - annc_rtidx, . . . );正確形式: (void) CCbinasc ( ( DMUNLONG ) loop_ptr - annc_rtidx , . . . );【檢查點(diǎn)9 】在多任務(wù)操作系統(tǒng)環(huán)境下是否考慮了函數(shù)的可重入性?說明在多任務(wù)的操作系統(tǒng)中,對于多任務(wù)共用的函數(shù),如果該函數(shù)用到了全局變量或靜態(tài)變量,需要注意到函數(shù)的可重入性。一般來說,如果函數(shù)只使用了內(nèi)部的非靜態(tài)局部變量,則該函數(shù)沒用可重入的問題【檢查點(diǎn)10 】當(dāng)一個(gè)指針被傳給一個(gè)函數(shù),并且被調(diào)用的函數(shù)試圖增加或減少這個(gè)指針?biāo)甘镜膬?nèi)容時(shí)是否出現(xiàn)了常見錯(cuò)誤?說明此時(shí)容易出現(xiàn)常見錯(cuò)誤案例案例一這個(gè)例子中,盡管 + 和 * 操作符擁有相同操作優(yōu)先級. 但它們是按從右到左的順序執(zhí)行的.錯(cuò)誤形式: * numretry +;正確形式:(* numretry) +;案例二另一個(gè)常見的錯(cuò)誤發(fā)生在當(dāng)你試圖調(diào)用一個(gè)函數(shù)并取其返回值,然后在一個(gè)條件判斷表達(dá)式中測試這個(gè)返回值時(shí).錯(cuò)誤形式: if ( ( rtc = _ims_open ( NPRD_CH ) ! = _SUCCESS ) ) 正確形式: if ( ( rtc = _ims_open( NPRD_CH ) ) ! = _SUCCESS ) 【檢查點(diǎn)11 】函數(shù)定義中增添了一個(gè)參數(shù)時(shí),是否有在所有該函數(shù)調(diào)用的場合完成對應(yīng)修改? 說明(函數(shù)被調(diào)用而參數(shù)未被充分傳遞的錯(cuò)誤也因之而生).如果新的參數(shù)是加到原來所定義的參數(shù)序列的開始或中間位置時(shí)問題將更加嚴(yán)重.發(fā)生這種問題時(shí),所有從這一點(diǎn)起前面已經(jīng)存在的參數(shù)都被錯(cuò)位了.下面這個(gè)例子說明這個(gè)問題. 案例函數(shù)調(diào)用傳送了三個(gè)參數(shù): DBnswch_mem( &omsg, &smtimr, grwsize ) ;但是函數(shù)定義了四個(gè)參數(shù): DBnswch_mem( OSPID, *omsg, *timr, grwsize) ;【檢查點(diǎn)13 】一組錯(cuò)誤類型是否也歸入這個(gè)子標(biāo)題所表示的錯(cuò)誤類型?說明調(diào)用 printf 及其相關(guān)的這組類型函數(shù)時(shí)傳遞了不恰當(dāng)數(shù)量的參數(shù)數(shù)量.問題來自于可能傳遞了更多或更少于轉(zhuǎn)義字符的變量參數(shù)給打印函數(shù).案例錯(cuò)誤形式: sprintf ( infile, /rclog/tmp.evl %d.5E3l );錯(cuò)誤形式: sprintf ( corclog, /log/cpcorc, 0 ); 【檢查點(diǎn)14 】fprintf ( ) 和 printf ( ) 是否被含糊理解?說明前者要求一個(gè)流指針作參數(shù)一而后者不需要.案例錯(cuò)誤形式: fprintf( system error, cdbcom not found in relation table en );錯(cuò)誤形式: printf( stdout, %s VPATH:en, Prompt);【檢查點(diǎn)15 】函數(shù)定義前是否已經(jīng)聲明過?說明程序在調(diào)用函數(shù)和存取全局?jǐn)?shù)據(jù)之前,必須先聲明函數(shù)的返回值類型和全局?jǐn)?shù)據(jù)的數(shù)據(jù)類型.通常,這些申明是頭文件的一部分,并且必須根據(jù)函數(shù)調(diào)用/數(shù)據(jù)存取的范圍予以定義.函數(shù)申明必須提供作為函數(shù)原型,也稱之為函數(shù)模板.函數(shù)原型 列出函數(shù)每個(gè)參數(shù)的類型以及函數(shù)返回參數(shù)的類型.通過這些函數(shù)原型和關(guān)于數(shù)據(jù)定義的頭文件確保被調(diào)函數(shù)/被存取的數(shù)據(jù)的正確定義.案例略如果被調(diào)函數(shù)/被存取的數(shù)據(jù)只是在某個(gè)特定的模塊中定義和使用,則無需專門的頭文件.如果被調(diào)函數(shù)/被存取的數(shù)據(jù)在某個(gè)特定模塊中定義但在子系統(tǒng)中多余一個(gè)模塊中使用,則對它們的申明(包括所用到的數(shù)據(jù)類型的定義)就應(yīng)該用到局部于該子系統(tǒng)的本地頭文件.如果被調(diào)函數(shù)/被存取的數(shù)據(jù)被其所定義的子系統(tǒng)之外的其他子系統(tǒng)所使用,那么其類型申明(包括所用到的數(shù)據(jù)類型的定義)就應(yīng)該用到系統(tǒng)全局的頭文件.【檢查點(diǎn)16 】函數(shù)參數(shù)是否清晰而簡潔?說明在接口上,簡潔是非常可取的特點(diǎn),因?yàn)楹瘮?shù)的參數(shù)的數(shù)量將影響程序接口的復(fù)雜度. 參數(shù)數(shù)量巨大將使得接口無法管理,代碼難以閱讀和理解, 接口的可維護(hù)性也會(huì)因其易于插入諸如修改參數(shù)后造成參數(shù)類型不匹配的錯(cuò)誤而受到損害. 數(shù)目7的法則(rule fo seven) 可能是函數(shù)調(diào)用時(shí)合理的最大的參數(shù)數(shù)目.一些接口的度量方法有益于管理函數(shù)的參數(shù),例如: 1) 每個(gè)函數(shù)的變量數(shù)目(輸入 + 輸出), 2) 與函數(shù)相關(guān)聯(lián)的函數(shù)的數(shù)目(調(diào)用和被調(diào)用).在一個(gè)結(jié)構(gòu)( struct 或者 typedef struct )中傳送所有或者大部分被調(diào)函數(shù)所需的參數(shù)數(shù)據(jù)是一個(gè)達(dá)到簡潔效果的有力方法.案例通常形式: SSfunction ( code, value, type, DBYES, msg.numb, msg.size, msg.unit.side, msg.unit.mod, msg.reg_make, DBNO);傳送指針: SSfunction ( code, value, type, DBYES, &msg, DBNO);傳送結(jié)構(gòu): SSfunction ( code, value, type, DBYES, msg, DBNO);如果傳送的是一個(gè)指向結(jié)構(gòu)的指針,那么被調(diào)函數(shù)可以改變這個(gè)結(jié)構(gòu)中元素的值.如果傳送整個(gè)結(jié)構(gòu),并且結(jié)構(gòu)包含的元素多于單獨(dú)傳遞每個(gè)元素所需傳遞的元素總數(shù)時(shí),程序設(shè)計(jì)者必須注意避免引入堆棧溢出問題.【檢查點(diǎn)17 】函數(shù)是否有正確的返回類型?說明 盡管C語言不要求必須明確定義或申明函數(shù)的返回值類型, 但如果函數(shù)沒有返回值則應(yīng)該定義或者申明為void類型. 如果函數(shù)未被明確的定義或申明其返回類型, 編譯器默認(rèn)其返回類型為int . 這種情況下,可能就難以清楚知道函數(shù)是否返回了參數(shù).因此為避免這種含糊,我們應(yīng)該清楚的定義和申明所有函數(shù)的返回值類型.為避免對函數(shù)進(jìn)一步使用時(shí)的含糊不清以及提高程序的可維護(hù)性,應(yīng)該運(yùn)用 void 數(shù)據(jù)類型通知編譯器函數(shù)將不會(huì)返回任何參數(shù). 因?yàn)榫幾g器無需為返回參數(shù)產(chǎn)生目標(biāo)代碼,因此也節(jié)約了堆??臻g同時(shí)提高系統(tǒng)性能. 不能在表達(dá)式中使用被定義或申明為 void 類型的函數(shù).函數(shù)中實(shí)際返回值的類型必須和函數(shù)類型相同或者必須強(qiáng)制轉(zhuǎn)換為函數(shù)類型. 如果函數(shù)的返回值無需被檢查或保留,那么函數(shù)返回值可以強(qiáng)制轉(zhuǎn)換為 (void), 這也將節(jié)約堆??臻g.案例 案例一未明確定義的函數(shù)類型默認(rèn)為 int 類型: 錯(cuò)誤形式: SSfunction ( ) return; 正確形式: void SSfunction ( ) return; 案例二盡管函數(shù) SSmodify ( ) 被申明為返回 void 類型,但它的返回值卻被檢查了。 錯(cuò)誤形式: void SSfunction ( ) void SSmodify ( ); if ( SSmodify ( ) = = GLSUCCESS ) 案例三如果調(diào)用一個(gè)有返回值的函數(shù),但是又無需檢測和保留該返回值,則應(yīng)該將其強(qiáng)制轉(zhuǎn)換為 void 類型. 錯(cuò)誤形式: RET_VAL SSfunction ( ) strncpy ( cost, GLctcst, 4); . . . 正確形式: RET_VAL SSfunction ( ) (void) strncpy ( cost, Glctcst, 4) ; . . . 案例四如果已定義為返回 void 類型的函數(shù)卻返回了一個(gè)值, 將不會(huì)被編譯器編譯. 錯(cuò)誤形式: void SSbad_func ( ) return ( 0 ); 【檢查點(diǎn)19 】是否有防御型的編程技巧?說明函數(shù)調(diào)用時(shí),程序應(yīng)該檢查參數(shù)傳遞是在所期待的取值范圍之內(nèi).這項(xiàng)原則有利于防止不加區(qū)別的使用指針以致于其值無法擔(dān)保其安全性.防御型檢查的程度需要和實(shí)時(shí)性要求相互制約平衡.例如,當(dāng)同一個(gè)參數(shù)傳遞到更低層次的函數(shù)時(shí),層層檢查的方法并不是絕對必要的.如果參數(shù)在最初的函數(shù)中進(jìn)行了檢查,就無需在每一次函數(shù)調(diào)用中再次檢查了,除非在過程中參數(shù)被修改了.案例 案例一在使用全局指針前,程序員應(yīng)該檢查指針的安全性. 正確形式: /* 對頭指針和尾指針進(jìn)行邊界檢查 */ if ( CRrptr CRMAX | | CRfptr CRMAX ) CRqrecover ( ); /* recover the CRA queue */ AUASRTA ( AUFALSE, CRA_$_ASRT); return ( CRERROR ); 案例二進(jìn)入函數(shù)時(shí),程序必須確保參數(shù)的安全性. 正確形式: short DBopgparm (parid, new_buf, pcrid, operation ) DMSYSID parid; char * new_buf; unsigned char pcrid; DMDBMODE operation; /* Global parameter operation */ . . . . . . /* 對 parid 作范圍檢查 */ if ( ( parid = dbparmax ) ) return ( DBSYS_ERR ); 變量【檢查點(diǎn)1 】是否使用了未初始化的變量?說明 該檢查點(diǎn)要求檢查在程序中使用的變量是否在使用前已經(jīng)初始化,確定初始化的位置和第一次調(diào)用的位置。 該類錯(cuò)誤絕大部分可以使用PC-LINT檢查出來,但對一些隱藏的較深的情況使用PC-LINT無法查出,需要特別注意。例如,對于全局變量A,在模塊B中初始化,在模塊C中調(diào)用。如果C在B前調(diào)用,顯然就會(huì)發(fā)生該類錯(cuò)誤,而PC-LINT是無法發(fā)現(xiàn)的案例略變量初始化的法則是: 1)局部和全局的常量 ( constant ) 必須在定義的位置進(jìn)行初始化. 2)非常量、非靜態(tài)的局部變量必須在代碼段中予以初始化,而不是在它們定義的位置 . 3)與進(jìn)程有關(guān)的全局變量應(yīng)該在每次進(jìn)程被重建時(shí)調(diào)用特定的函數(shù)對它們進(jìn)行初始化.【檢查點(diǎn)2 】是否定義了變量但是沒有使用?規(guī)范性說明略案例略【檢查點(diǎn)3 】是否存在類型不匹配的賦值操作說明該檢查點(diǎn)主要檢查程序中是否有不同類型數(shù)據(jù)相互轉(zhuǎn)換造成的錯(cuò)誤。在程序中,開啟定時(shí)器的正確書寫為:long time;time = 10000;OSWAIT(10000, time);錯(cuò)誤書寫:char time;time = 10000;OSWAIT(10000, time);在這里,執(zhí)行語句time = 10000;,然后作為第二個(gè)參數(shù)傳遞到函數(shù)OSWAIT()以產(chǎn)生10秒的等待。但是,由于變量time為單字節(jié),所以10000被截取為16進(jìn)制。因此,該代碼只等待16毫秒,而不是10秒。【檢查點(diǎn)4 】是否存在類型不匹配的比較操作說明在循環(huán)終止條件的判斷中,不同類型變量的比較操作是容易造成死循環(huán)錯(cuò)誤的地方,同時(shí)開發(fā)人員容易忽視的地方,在代碼審查中值得多加留意。案例在下列循環(huán)中:while( ftell(fp)= 0) /*將出現(xiàn)下溢*/ . /* program code*/當(dāng)size等于0時(shí),再減1不會(huì)小于0,而是0xFF,故程序是一個(gè)死循環(huán)。應(yīng)如下修改。char size; /* 從unsigned char 改為char*/while (size- = 0) . /* program code */【檢查點(diǎn)7 】是否沒有判斷unsigned為最大值而直接加1(上溢)?說明unsigned為最大值時(shí),加1則為0,產(chǎn)生上溢?!緳z查點(diǎn)8 】調(diào)用函數(shù)時(shí)傳入?yún)?shù)和是否和函數(shù)原型申明不一致?說明略案例在函數(shù)INT DebugMsgProc(char byMsg0, char byMsg1)函數(shù)中,兩個(gè)形參都是char型。如果實(shí)際傳入的參數(shù)都是BYTE型(unsigned char),函數(shù)中的如下語句: PrintfE(PID_RED, %d ticks time out!,byMsg1);在byMsg1大于127時(shí),輸出錯(cuò)誤的結(jié)果?!緳z查點(diǎn)9 】變量的計(jì)算和取值順序是否清淅?說明有的編譯器從右到左計(jì)算表達(dá)式而有的是從左到右, 取決與不同的方法。變量可能將相互偏離一個(gè)取值。無論以什么為基準(zhǔn),這樣的代碼是含糊不清的。案例錯(cuò)誤形式:for ( idx = 0 ; idx 40; dispstring idx = COTsuccess idx+ ) ;正確形式:for ( idx = 0 ; idx cindex = (cindex + 1) & 0x7F;這里,值被0X7F做了采樣(即采樣7位)之后進(jìn)行賦值操作. 因?yàn)?cindex 在數(shù)據(jù)結(jié)構(gòu)中僅僅被分配了6比特的存儲(chǔ)空間,賦值的數(shù)據(jù)被修剪了,導(dǎo)致了嚴(yán)重的域問題.注意決不可忽視變量賦值的過程.必須檢查確保所有的變量不能賦以超過變量本身數(shù)據(jù)結(jié)構(gòu)可以容納的數(shù)值.【檢查點(diǎn)11 】是否將局部變量在函數(shù)體外使用?說明局部變量只在函數(shù)體中有效案例案例一下面的函數(shù)對變量a的操作是錯(cuò)誤的:int *foo (void) int a; /* code */ /*a 使局部變量,其地址位于堆棧中 ,返回a的指針是沒有意義的。*/ return &a; 案例二在SendToOtherOMU()函數(shù)中,局部數(shù)組變量 unsigned char ucpToMsg300 的地址被作為消息傳送給MSG_QUEUE隊(duì)列。由于局部變量的生存期僅在函數(shù)運(yùn)行期內(nèi),當(dāng)函數(shù)退出后,局部變量自動(dòng)失效,導(dǎo)致隊(duì)列中的消息不確定int SendToOtherOMU(unsigned char * ucpMsg)int err;unsigned char ucpToMsg300; /* 定義存放消息局部變量 */UcpToMsg0=MSG_SEND_DATA;MemCopy(ucpMsg,ucpToMsg+1,ucpMsg0+1); /* 形成消息內(nèi)容 */sc_qpost(MSG_QUEUE,(char *)ucpToMsg,&err); /* 將數(shù)組首地址傳遞給函數(shù) */If(err!=0)Return(NACK_SC_QPOST_ERR);Return(0);在上述代碼中,sc_qpost(MSG_QUEUE,(char *)ucpToMsg,&err) 語句 將ucpToMsg 數(shù)組的首地址放入MSG_QUEUE隊(duì)列,當(dāng)函數(shù)退出后,局部變量失效,當(dāng)隊(duì)列中的消息不能及時(shí)取走時(shí),可能出現(xiàn) ucpToMsg 地址開始的內(nèi)存被覆蓋,導(dǎo)致消息數(shù)據(jù)發(fā)生變化?!緳z查點(diǎn)12 】在return語句前,占有的資源是否被釋放?說明看見return語句,尤其是函數(shù)中間的異常返回語句。看到這種語句,就需要折回頭去看看前面有沒有分配資源。前面分配的任何資源(包括內(nèi)存,端口,等等),在異常返回處需要一并釋放。案例在ULONG AllocateVl(void *pMsgEnv)函數(shù)中, if ( pValue-rxTDscrIndex) rc = TD_IncreaseTDRefer(pValue-rxTDscrIndex); if (rc) #if PVC_APS_ENABLE = YES APS_DecrProtectConf(void);#endif return PVC_TRAFF_ERROR; newVlEntry.rxIndex = pValue-rxTDscrIndex; 指針【檢查點(diǎn)1 】使用指針時(shí)是否先判斷為空? 說明指針在使用前應(yīng)該初始化,或者賦值?!緳z查點(diǎn)2 】對數(shù)組amn是否正確使用“ai+j ”和“&ai+j ”指針?說明C語言中規(guī)定數(shù)組名代表數(shù)組的首地址。對任意的二維數(shù)組 amn, a表示本數(shù)組的第1個(gè)元素的地址,a + i 表示本數(shù)組第 i 行的首地址。 ai 代表 amn 第 i 行的首地址(即第 i 行第 0 列元素的地址),&ai 也表示第 i 行第 0 列元素的地址。 但ai與&ai 的含義卻是不同的,是兩種不同類型的指針,在指針運(yùn)算時(shí)就會(huì)表現(xiàn)出不同,它們處理下一單元的方向是不一樣的:&ai指向行,而ai指向列。對 &ai+j 和 ai+j 而言,只有當(dāng) j 為0 時(shí),&ai+j和ai+j 的值才相等,即都指向第 i 行第 0 列的元素。 例如, 定義了一個(gè)二維數(shù)組a66, 當(dāng)j = 0.5 時(shí), ai + j和&ai+ j 產(chǎn)生的地址如下: ai + j :按行產(chǎn)生地址,即 ai0、ai1 . ai5 的地址 &ai + j :按列產(chǎn)生地址,即ai0、ai+10 . ai+j0的地址,也就是aij 數(shù)組第 i + j 行的首地址。 如對&ai進(jìn)行強(qiáng)制轉(zhuǎn)換,&ai和ai就等價(jià)了,即(_UC*)&ai也按行的方向計(jì)算地址。案例略【檢查點(diǎn)3 】對指針加減法操作是否超出數(shù)據(jù)類型的邊界?說明運(yùn)用指針來提供記法上的便利并且提高程序的效率,同時(shí)也使得代碼占用更少的內(nèi)存、執(zhí)行得更快.指針的遞增和遞減量規(guī)定為指針?biāo)甘镜臄?shù)據(jù)類型的數(shù)據(jù)空間大小.對指針加減法操作不要超出數(shù)據(jù)類型的邊界.以下顯示一個(gè)對指針的增減操作超出邊界的例子.案例錯(cuò)誤形式: short valueexmaxval; short *value_pointer; value_pointer = value; value_pointer += (exmaxval + 1 );【檢查點(diǎn)3 】是否正確地使用數(shù)組函數(shù)參數(shù)的指針?說明沒有下標(biāo)的數(shù)組名是指向該數(shù)組的指針.需特別指明沒有下標(biāo)的數(shù)組名產(chǎn)生的是一個(gè)指向數(shù)組第一個(gè)元素的指針.將函數(shù)參數(shù)申明為數(shù)組并使用其名稱,而不是指向數(shù)組的指針.如以下所示.內(nèi)存操作【檢查點(diǎn)1 】是否對數(shù)組進(jìn)行了越界操作?說明內(nèi)存操作主要是指對數(shù)組、指針、內(nèi)存地址等的操作。內(nèi)存操作越界是軟件系統(tǒng)主要錯(cuò)誤之一,后果往往非常嚴(yán)重,所以當(dāng)我們進(jìn)行這些操作時(shí)一定要仔細(xì)小心。案例案例一在C語言中,定義數(shù)組a10,則有效的數(shù)組元素為:a0, a1, ., a9,在程序中使用a10是錯(cuò)誤的?!緳z查點(diǎn)2 】內(nèi)存拷貝時(shí)是否判斷了長度?【檢查點(diǎn)3 】申請內(nèi)存后是否判斷了內(nèi)存申請成功?【檢查點(diǎn)4 】對異常情況的處理時(shí)是否直接return而忘記了釋放內(nèi)存?說明對于動(dòng)態(tài)申請和釋放的內(nèi)存使用經(jīng)常存在以下問題:1、異常情況的處理,直接調(diào)用了return,忘記了釋放內(nèi)存。2、switch語句沒有相應(yīng)的default處理或default處理中也遺漏了釋放內(nèi)存的操作。3、if語句沒有相應(yīng)的else分支,原理同上。4、連續(xù)申請兩個(gè)內(nèi)存塊的時(shí)候,若第二個(gè)申請不成功而函數(shù)返回時(shí),應(yīng)釋放第一個(gè)申請的內(nèi)存塊。實(shí)際上存在著第二個(gè)申請不成功就直接return的情況。案例案例一下面的代碼段是一個(gè)異常情況內(nèi)存沒有釋放的例子: . pRecord = new charpTable-GetRecordLength();assert(pRecord != NULL);if (pTable-GoTop(FALSE) != DBIERR_NONE)return; /* 如果從這里返回,pRecord將得不到釋放*/ . pTable-Close();delete pRecord; 【檢查點(diǎn)5 】終止一項(xiàng)任務(wù)時(shí)是否完全釋放內(nèi)存?說明略案例略循環(huán)for,while循環(huán)語句 【檢查點(diǎn)1 】是否在for語句后誤用了“;”【檢查點(diǎn)2 】是否在while 語句后誤用了“;”【檢查點(diǎn)3 】控制循環(huán)的變量是否有遞增(遞減)操作?【檢查點(diǎn)4 】是否在多層循環(huán)中使用同一個(gè)循環(huán)控制變量?【檢查點(diǎn)5 】多層循環(huán)中的break對應(yīng)關(guān)系是否正確?【檢查點(diǎn)6 】循環(huán)邊界是否正確說明該檢查點(diǎn)需要檢查程序中所有的循環(huán)邊界是否設(shè)置正確。要求確保程序不會(huì)進(jìn)入死循環(huán)。常犯的錯(cuò)誤是對于for循環(huán),循環(huán)的邊界大于循環(huán)變量的取值范圍,這樣就會(huì)直接導(dǎo)致死循環(huán)。比如用unsigned char型變量作為循環(huán)變量,而循環(huán)邊界大于unsigned char型變量的最大值255。對于使用while循環(huán)進(jìn)行鏈表操作往往容易引起更隱蔽的死機(jī)錯(cuò)誤。這種錯(cuò)誤常常只有在很特殊的情況下才會(huì)重現(xiàn),需要仔細(xì)檢查。建議在使用while循環(huán)比較復(fù)雜的鏈表操作時(shí),可以在while循環(huán)中增加循環(huán)變量判斷或改寫成for循環(huán)。這樣即便出現(xiàn)死循環(huán)的條件,但是只要對循環(huán)變量進(jìn)行控制,也能夠退出循環(huán)。案例 案例一在如下對鏈表的操作代碼: while( go != NO_JOB)go = JobTablego.NextJob;在實(shí)際環(huán)境中,由于其他異常的情況造成鏈表被改成了循環(huán)鏈表,從而在這里陷入了死循環(huán)。對于這種代碼,可以通過改造加入保護(hù),從而防止在這里陷入死循環(huán)。這是實(shí)際中改造后的代碼: for( protect=0; (protectMAX_JOBS)&(go != NO_JOB); protect+ ) go = JobTablego.NextJob; 案例二盡管局部數(shù)組proname 的長度分配了正確的數(shù)量, 但是因?yàn)檠h(huán)的邊界限制設(shè)定得太高,數(shù)組最終被越界檢索了.錯(cuò)誤形式: char proname 10 ; . . . for (i = 0; i 14; i + ) pronamei = *argv 0 ; . . .案例三循環(huán)的邊界測試可能持續(xù)的太遠(yuǎn).在這個(gè)例子當(dāng)中,變量 featent.curpos 只能測試小于,而不能是等于,NBISTRFTENT的情況.錯(cuò)誤形式: for( ; ( featent.curpos = NBISTRMFTENT & .正確形式: for( ; ( featent.curpos NBISTRNFTNT & .為避免類似微妙的錯(cuò)誤,所有的循環(huán)測試的取值范圍應(yīng)該仔細(xì)的檢查.案例四U8* DEV_IfTypeToString(U32

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論