華為軟體編程規範學習(九)--品質保證
9-1:在軟體設計過程中構築軟體品質
9-2:代碼品質保證優先原則
(1)正確性,指程式要實現設計要求的功能。
(2)穩定性、安全性,指程式穩定、可靠、安全。
(3)可測試性,指程式要具有良好的可測試性。
(4)規範/可讀性,指程式書寫風格、命名規則等要符合規範。
(5)全域效率,指軟體系統的整體效率。
(6)局部效率,指某個模組/子模組/函數的本身效率。
(7)個人表達方式/個人方便性,指個人編程習慣。
9-3:只引用屬於自己的存貯空間
說明:若模組封裝的較好,那麼一般不會發生非法引用他人的空間。
9-4:防止引用已經釋放的記憶體空間
說明:在實際編程過程中,稍不留心就會出現在一個模組中釋放了某個記憶體塊(如C語言指標),而另一模組在隨後的某個時刻又使用了它。要防止這種情況發生。
9-5:過程/函數中分配的記憶體,在過程/函數退出之前要釋放
9-6:過程/函數中申請的(為開啟檔案而使用的)檔案控制代碼,在過程/函數退出之前要關閉
說明:分配的記憶體不釋放以及檔案控制代碼不關閉,是較常見的錯誤,而且稍不注意就有可能發生。這類錯誤往往會引起很嚴重後果,且難以定位。
樣本:下函數在退出之前,沒有把分配的記憶體釋放。
typedef unsigned char BYTE;int example_fun( BYTE gt_len, BYTE *gt_code ){ BYTE *gt_buf; gt_buf = (BYTE *) malloc (MAX_GT_LENGTH); ... //program code, include check gt_buf if or not NULL. /*global title length error */ if(gt_len > MAX_GT_LENGTH) { return GT_LENGTH_ERROR; // 忘了釋放gt_buf } ... // other program code}
應改為如下。
int example_fun( BYTE gt_len, BYTE *gt_code ){ BYTE *gt_buf; gt_buf = (BYTE * ) malloc ( MAX_GT_LENGTH ); ... // program code, include check gt_buf if or not NULL. /*global title length error */ if(gt_len > MAX_GT_LENGTH) { free( gt_buf ); // 退出之前釋放gt_buf return GT_LENGTH_ERROR; } ... // other program code}
9-7:防止記憶體操作越界
說明:記憶體操作主要是指對數組、指標、記憶體位址等的操作。記憶體操作越界是軟體系統主要錯誤之一,後果往往非常嚴重,所以當我們進行這些操作時一定要仔細小心。
樣本:假設某軟體系統最多可由10個使用者同時使用,使用者號為1-10,那麼如下程式存在問題。
#define MAX_USR_NUM 10unsigned char usr_login_flg[MAX_USR_NUM]= "";voidset_usr_login_flg( unsigned char usr_no ){ if(!usr_login_flg[usr_no]) { usr_login_flg[usr_no]= TRUE; }}
當usr_no為10時,將使用usr_login_flg越界。可採用如下方式解決。
voidset_usr_login_flg( unsigned char usr_no ){ if(!usr_login_flg[usr_no - 1]) { usr_login_flg[usr_no - 1]= TRUE; }}
9-8:認真處理常式所能遇到的各種出錯情況
9-9:系統運行之初,要初始化有關變數及運行環境,防止未經初始化的變數被引用
9-10:系統運行之初,要對載入到系統中的資料進行一致性檢查
說明:使用不一致的資料,容易使系統進入混亂狀態和不可知狀態。
9-11:嚴禁隨意更改其它模組或系統的有關設定和配置
說明:編程時,不能隨心所欲地更改不屬於自己模組的有關設定如常量、數組的大小等。
9-12:不能隨意改變與其它模組的介面
9-13:充分瞭解系統的介面之後,再使用系統提供的功能
樣本:在B型機的各模組與作業系統的介面函數中,有一個要由各模組負責編寫的初始化過程,此過程在軟體系統載入完成後,由作業系統發送的初始化訊息來調度。因此就涉及到初始化訊息的類型與訊息發送的順序問題,特別是訊息順序,若沒搞清楚就開始編程,很容易引起嚴重後果。以下樣本引自B型曾出現過的實際代碼,其中使用了FID_FETCH_DATA與FID_INITIAL初始化訊息類型,注意B型機的系統是在FID_FETCH_DATA之前發送FID_INITIAL的。
MID alarm_module_list[MAX_ALARM_MID];int FARSYS_ALARM_proc( FID function_id, int handle ){ _UI i, j; switch ( function_id ) { ... // program code case FID_INITAIL: for (i = 0; i < MAX_ALARM_MID; i++) { if (alarm_module_list[i]== BAM_MODULE // **) || (alarm_module_list[i]== LOCAL_MODULE) { for(j = 0; j < ALARM_CLASS_SUM; j++) { FAR_MALLOC( ... ); } } } ... // program code break; case FID_FETCH_DATA: ... // program code Get_Alarm_Module( ); // 初始化alarm_module_list break; ... // program code }}
由於FID_INITIAL是在FID_FETCH_DATA之前執行的,而初始化alarm_module_list是在FID_FETCH_DATA中進行的,故在FID_INITIAL中(**)處引用alarm_module_list變數時,它還沒有被初始化。這是個嚴重錯誤。
應如下改正:要麼把Get_Alarm_Module函數放在FID_INITIAL中(**)之前;要麼就必須考慮(**)處的判斷語句是否可以用(不使用alarm_module_list變數的)其它方式替代,或者是否可以取消此判斷語句。
9-14:編程時,要防止差1錯誤
說明:此類錯誤一般是由於把“<=”誤寫成“<”或“>=”誤寫成“>”等造成的,由此引起的後果,很多情況下是很嚴重的,所以編程時,一定要在這些地方小心。當編完程式後,應對這些操作符進行徹底檢查。
9-15:要時刻注意易混淆的操作符。當編完程式後,應從頭至尾檢查一遍這些操作符,以防止拼字錯誤
說明:形式相近的操作符最容易引起誤用,如C/C++中的“=”與“==”、“|”與“||”、“&”與“&&”等,若拼字錯了,編譯器不一定能夠檢查出來。
樣本:如把“&”寫成“&&”,或反之。
ret_flg = (pmsg->ret_flg & RETURN_MASK);
被寫為:
ret_flg = (pmsg->ret_flg && RETURN_MASK);
rpt_flg = (VALID_TASK_NO( taskno ) && DATA_NOT_ZERO( stat_data ));
被寫為:
rpt_flg = (VALID_TASK_NO( taskno ) & DATA_NOT_ZERO( stat_data ));
9-16:有可能的話,if語句盡量加上else分支,對沒有else分支的語句要小心對待;switch語句必須有default分支
9-17:Unix下,多線程的中的子線程退出必需採用主動退出方式,即子線程應return出口。
9-18:不要濫用goto語句。
說明:goto語句會破壞程式的結構性,所以除非確實需要,最好不使用goto語句。
其他
9-1:不使用與硬體或作業系統關係很大的語句,而使用建議的標準語句,以提高軟體的可移植性和可重用性
9-2:除非為了滿足特殊需求,避免使用嵌入式彙編
說明:程式中嵌入式彙編,一般都對可移植性有較大的影響。
9-3:精心地構造、劃分子模組,並按“介面”部分及“核心”部分合理地組織子模組,以提高“核心”部分的可移植性和可重用性
說明:對不同產品中的某個功能相同的模組,若能做到其核心部分完全或基本一致,那麼無論對產品的測試、維護,還是對以後產品的升級都會有很大協助。
9-4:精心構造演算法,並對其效能、效率進行測試
9-5:對較關鍵的演算法最好使用其它演算法來確認
9-6:時刻注意運算式是否會上溢、下溢
樣本:如下程式將造成變數下溢。
unsigned char size ;
while (size-- >=0) // 將出現下溢{ ... // program code}
當size等於0時,再減1不會小於0,而是0xFF,故程式是一個死迴圈。應如下修改。
char size; // 從unsigned char 改為charwhile (size-- >=0){ ... // program code}
9-7:使用變數時要注意其邊界值的情況
樣本:如C語言中字元型變數,有效值範圍為-128到127。故以下運算式的計算存在一定風險。
char chr = 127;int sum = 200;chr += 1; // 127為chr的邊界值,再加1將使chr上溢到-128,而不是128。sum += chr; // 故sum的結果不是328,而是72。若chr與sum為同一種類型,或運算式按如下方式書寫,可能會好些。sum = sum + chr + 1;
9-8:留心程式機器碼大小(如指令空間大小、資料空間大小、堆棧空間大小等)是否超出系統有關限制
9-9:為使用者提供良好的介面介面,使使用者能較充分地瞭解系統內部運行狀態及有關係統出錯情況
9-10:系統應具有一定的容錯能力,對一些錯誤事件(如使用者誤操作等)能進行自動補救
9-11:對一些具有危險性的作業碼(如寫硬碟、刪資料等)要仔細考慮,防止對資料、硬體等的安全構成危害,以提高系統的安全性
9-12:使用第三方提供的軟體開發套件或控制項時,要注意以下幾點:
(1)充分瞭解應用介面、使用環境及使用時注意事項。
(2)不能過分相信其正確性。
(3)除非必要,不要使用不熟悉的第三方工具包與控制項。
說明:使用工具包與控制項,可加快程式開發速度,節省時間,但使用之前一定對它有較充分的瞭解,同時第三方工具包與控制項也有可能存在問題。
9-13:資源檔(多語言版本支援),如果資源是對語言敏感的,應讓該資源與原始碼檔案脫離,具體方法有下面幾種:使用單獨的資源檔、DLL檔案或其它單獨的描述檔案(如資料庫格式)