?? 編程規范與范例(5).txt
字號:
[編程技巧]編程規范與范例(5)
程序匠人 發表于 2005-8-27 20:18:00 閱讀全文(216) | 回復(0) | 引用(0)
編程規范與范例(5)
〖文章轉載或出處〗≡中國電子技術信息網≡ 網址:www.CETINet.com
編程規范與范例(5)
目 錄
1 排版 6
2 注釋 11
3 標識符命名 18
4 可讀性 20
5 變量、結構 22
6 函數、過程 28
7 可測性 36
8 程序效率 40
9 質量保證 44
10 代碼編輯、編譯、審查 50
11 代碼測試、維護 52
12 宏 53
9 質量保證
¹ 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 10
unsigned char usr_login_flg[MAX_USR_NUM]= "";
void set_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越界。可采用如下方式解決。
void set_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 FAR SYS_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 改為char
while (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文件或其它單獨的描述文件(如數據庫格式)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -