1 文件與目錄
1.1 文件命名
- 1 文件與目錄的命名可以使用的字符為
[A-Z, a-z, 0-9, ., _, -]
。 - 2 文件擴展名使用小寫字母,如
.c
、.h
。 - 3 文件的命名要準確清晰地表達其內(nèi)容,同時文件名應(yīng)該精煉,在文件名中可以適當(dāng)?shù)厥褂每s寫。
例如:
- 模塊名稱簡寫+文件名稱,如mpMain.c、mpDisp.h
- 直接使用文件名稱,如main.c、disp.h
- 4 文件命名采用小駝峰命名法。
1.2 目錄
- 5 一個軟件包或者邏輯組件的所有頭文件和源文件建議放在一個單獨的目錄下,以便查找。
- 6 對于頭(源)文件的段落安排,建議如下:
- 文件頭注釋 <適用于頭文件和源文件>
- 防止重復(fù)應(yīng)用頭文件的設(shè)置 <適用于頭文件>
- 頭文件包含部分 <適用于頭文件和源文件>
- 宏定義部分 <適用于頭文件和源文件>
- 枚舉常量聲明部分 <適用于頭文件和源文件>
- 類型聲明和定義部分,如
struct
、union
、typedef
等 <適用于頭文件和源文件>- 全局變量聲明部分 <適用于頭文件和源文件>
- 文件級變量聲明 <適用于源文件>
- 全局函數(shù)聲明 <適用于頭文件>
- 文件級函數(shù)聲明 <適用于源文件>
- 函數(shù)實現(xiàn),按函數(shù)聲明的順序 <適用于源文件>
- 文件尾注釋 <適用于頭文件和源文件>
- 7 包含頭文件時使用相對路徑,禁止使用絕對路徑
示例:
#include "/project/inc/hello.h" /* NG: 不應(yīng)使用絕對路徑 */
#include "../inc/hello.h" /* OK: 可以使用相對路徑 */
- 8 在引用頭文件時,使用
<>
來引用預(yù)定義或者特定目錄的頭文件,使用""
來引用當(dāng)前目錄或者路徑相對于當(dāng)前目錄的頭文件。
示例:
#include <stdio.h> /* 標準頭文件 */
#include <projdefs.h> /* 工程指定目錄頭文件 */
#include "global.h" /* 當(dāng)前目錄頭文件 */
#include "inc/config.h" /* 路徑相對于當(dāng)前目錄的頭文件 */
- 9 為了防止頭文件被重復(fù)引用,應(yīng)當(dāng)用
#ifndef/#define/#endif
結(jié)構(gòu)產(chǎn)生預(yù)處理塊。
示例:
#ifndef __DISP_H__ /* 文件名前名加兩個下劃線“__”,后面加“_H__” */
#define __DISP_H__
//......
#endif
- 10 頭文件中只存放 “聲明”而不存放 “定義”。
示例:
/* 模塊1頭文件:module1.h */
extern int a=5; /* OK: 在模塊1的.h文件中聲明變量 */
uint8_t g_ucPara; /* NG: 在模塊1的.h文件中定義全局變量g_ucPara*/
2 排版
- 1 程序塊要采用縮進風(fēng)格編寫,縮進的空格數(shù)為4個。
- 2 相對獨立的程序塊之間、變量說明之后 必須加空行。
示例:
void demoFunc( void )
{
uint8_t i;
/* 此處為空行, 局部變量和語句間空一行 */
/* 功能塊1 */
for ( i = 0; i < 10; i++ )
{
//...
}
/* 此處為空行,不同的功能塊間空一行*/
/*功能塊2*/
for ( i = 0; i < 20; i++ )
{
//...
}
}
- 3 較長的語句或函數(shù)過程參數(shù)( >80字符)要分成多行書寫,長表達式要在低優(yōu)先級操作符處劃分新行,操作符放在新行之首,劃分出的新行要進行適當(dāng)?shù)目s進,使排版整齊,語句可讀。
示例:
if( ( ucParam1 == 0 ) && ( ucParam2 == 0 ) && ( ucParam3 == 0 )
|| ( ucParam4 == 0 ) )<----長表達式需要換行書寫
{
//...
}
- 4 不允許把多個短語句寫在一行中,即一行只寫一條語句。
示例:
rect.length = 0; rect.width = 0; // NG: 一行多條語句
rect.length = 0; // OK: 一行一條語句
rect.width = 0;
5 對齊縮進為 4個空格字符。
6 函數(shù)或過程的開始、結(jié)構(gòu)的定義及循環(huán)、判斷等語句中的代碼都要采用縮進風(fēng)格,case語句下的情況處理語句也要遵從語句縮進要求。
7 程序塊的分界符(如大括號
{
、}
)應(yīng)各獨占一行并且位于同一列,同時與引用它們的語句左對齊。在函數(shù)體的開始、類的定義、結(jié)構(gòu)的定義、枚舉的定義以及if
、for
、do
、while
、switch
、case
語句中的程序都要采用如上的縮進方式。對于與規(guī)則不一致的現(xiàn)存代碼,應(yīng)優(yōu)先保證同一模塊中的風(fēng)格一致性。
示例:
void func( void )
{
for(...){ /* NG: {需要單獨占用一行 */
//.../*programcode*/
}
for(...)
{ /* 規(guī)范的寫法 */
//.../*programcode*/
}
}
8 在兩個以上的關(guān)鍵字、變量、常量進行對等操作時,它們之間的操作符之前、之后或者前后要加空格,給操作符留空格時不要連續(xù)留兩個以上空格。
(1) 逗號、分號只在后面加空格。
int_32 a, b, c;
- (2) 比較操作符,賦值操作符
=
、+=
,算術(shù)操作符+
、%
,邏輯操作符&&
、&
,位域操作符<<
、^
等雙目操作符的前后加空格。
if( current_time >= MAX_TIME_VALUE )
{
a = b + c;
}
a *= 2;
a = b ^ 2;
- (3)
!
、~
、++
、--
、&
(地址運算符)等單目操作符前后不加空格。
*p = 'a'; /* 內(nèi)容操作"*"與內(nèi)容之間 */
flag = !isEmpty; /* 非操作"!"與內(nèi)容之間 */
p = &mem; /* 地址操作"&"與內(nèi)容之間 */
i++; /* "++","--"與內(nèi)容之間 */
- (4)
->
、.
前后不加空格。
p->id = pid; /* "->"指針前后不加空格 */
- (5)
if
、for
、while
、switch
等與后面的括號間應(yīng)加空格,使if
等關(guān)鍵字更為突出、明顯, 函數(shù)名與其后的括號之間不加空格,以與保留字區(qū)別開。
if ( ( a >= b ) && ( c > d ) )
3 注釋
- 1 一般情況下,源程序有效注釋量必須在20%以上。
- 2 在文件的開始部分,應(yīng)該給出關(guān)于文件版權(quán)、內(nèi)容簡介、修改歷史等項目的說明。具體的格式請參見如下的說明。在創(chuàng)建代碼和每次更新代碼時,都必須在文件的歷史記錄中標注版本號、日期、作者、更改說明等項目。其中的版本號的格式為兩個數(shù)字字符和一個英文字母字符。數(shù)字字符表示大的改變,英文字符表示小的修改。如果有必要,還應(yīng)該對其它的注釋內(nèi)容也進行同步的更改。注意:注釋第一行星號要求為76個,結(jié)尾行星號為1個。
/****************************************************************************
*Copyright(C),2010-2011,武漢漢升汽車傳感系統(tǒng)有限責(zé)任公司
*文件名: main.c
*內(nèi)容簡述:*
*文件歷史:
*版本號日期作者說明
*01a2010-07-29王江河創(chuàng)建該文件
*01b2010-08-20王江河改為可以在字符串中發(fā)送回車符
*02a2010-12-03王江河增加文件頭注釋
*/
- 3 對于函數(shù),在函數(shù)實現(xiàn)之前,應(yīng)該給出和函數(shù)的實現(xiàn)相關(guān)的足夠而精練的注釋信息。內(nèi)容包括本函數(shù)功能介紹,調(diào)用的變量、常量說明,形參說明,特別是全局、全程或靜態(tài)變量(慎用靜態(tài)變量),要求對其初值,調(diào)用后的預(yù)期值作詳細的闡述。具體的書寫格式和包含的各項內(nèi)容請參見如下的例子。
示例:
下面這段函數(shù)的注釋比較標準,當(dāng)然,并不局限于此格式,但上述信息建議要包含在內(nèi)。
/****************************************************************************
*函數(shù)名:SendToCard()
*功能:向讀卡器發(fā)命令,如果讀卡器進入休眠,則首先喚醒它
*輸入:全局變量gaTxCard[]存放待發(fā)的數(shù)據(jù)
*全局變量gbTxCardLen存放長度
*輸出:無
*/
4 邊寫代碼邊注釋,修改代碼同時修改相應(yīng)的注釋,以保證注釋與代碼的一致性。不再有用的注釋要刪除。
5 注釋的內(nèi)容要清楚、明了,含義準確,防止注釋二義性。
說明:錯誤的注釋不但無益反而有害。注釋主要闡述代碼做了什么(What),或者如果有必要的話,闡述為什么要這么做(Why),注釋并不是用來闡述它究竟是如何實現(xiàn)算法(How)的。
- 6 避免在注釋中使用縮寫,特別是非常用縮寫。
說明:在使用縮寫時或之前,應(yīng)對縮寫進行必要的說明。
- 7 注釋應(yīng)與其描述的代碼靠近,對代碼的注釋應(yīng)放在其上方或右方(對單條語句的注釋)相鄰位置,不可放在下面,如放于上方則需與其上面的代碼用空行隔開。
例1:不規(guī)范的寫法
void func( void )
{
/*獲取復(fù)本子系統(tǒng)索引和網(wǎng)絡(luò)指示器*/
//NG: 不規(guī)范的寫法,此處不應(yīng)該空行
repssnInd = ssnData[index].repssnIndex;
repssnNi = ssnData[index].ni;
}
例2:不規(guī)范的寫法
void func( void )
{
repssnInd = ssnData[index].repssnIndex;
repssnNi = ssnData[index].ni;
/* 獲取復(fù)本子系統(tǒng)索引和網(wǎng)絡(luò)指示器 */ // NG: 不規(guī)范的寫法,應(yīng)該在語句前注釋
}
例3:規(guī)范的寫法
void func( void )
{
/*獲取復(fù)本子系統(tǒng)索引和網(wǎng)絡(luò)指示器*/
repssnInd = ssnData[index].repssnIndex;
repssnNi = ssnData[index].ni;
}
例4:不規(guī)范的寫法,顯得代碼過于緊湊
void func( void )
{
/*獲取復(fù)本子系統(tǒng)索引*/
repssnInd = ssnData[index].repssnIndex;
/* *獲取復(fù)本子系統(tǒng)網(wǎng)絡(luò)指示器 */ // NG: 代碼與上一行注釋之間需要空行
repssnNi = ssnData[index].ni;
}
例5:規(guī)范的寫法
void func( void )
{
/*獲取復(fù)本子系統(tǒng)索引*/
repssnInd = ssnData[index].repssnIndex;
/* *獲取復(fù)本子系統(tǒng)網(wǎng)絡(luò)指示器 */
repssnNi = ssnData[index].ni;
}
- 8 注釋與所描述內(nèi)容進行同樣的縮排。
- 9 對變量的定義和分支語句(條件分支、循環(huán)語句等)必須編寫注釋。
說明:這些語句往往是程序?qū)崿F(xiàn)某一特定功能的關(guān)鍵,對于維護人員來說,良好的注釋幫助更好的理解程序,有時甚至優(yōu)于看設(shè)計文檔。
- 10 對于switch語句下的case語句,如果因為特殊情況需要處理完一個case后進入下一個case處理,必須在該case語句處理完、下一個case語句前加上明確的注釋。
說明:這樣比較清楚程序編寫者的意圖,有效防止無故遺漏break語句。示例(注意斜體加粗部分):
switch ( cmd )
{
case CMD_DOWN:
ProcessDown();
break;
case CMD_FWD:
ProcessFwd();
if (...)
{
...
break;
}
else
{
ProcessCFW_B(); /*now jump into case CMD_A*/
}
case CMD_A:
ProcessA();
break;
default:
break;
}
- 11 注釋格式盡量統(tǒng)一,建議使用“/……/”,因為C++注釋“//”并不被所有C編譯器支持。
- 12 注釋應(yīng)考慮程序易讀及外觀排版的因素,使用的語言若是中、英兼有的,建議多使用中文,除非能非常流利準確的用英文表達。
說明:注釋語言不統(tǒng)一,影響程序易讀性和外觀排版,出于對維護人員的考慮,建議使用中文。
4 標識符命名
- 1 標識符的命名要清晰、明了,有明確含義,同時使用完整的單詞或大家基本可以理解的縮寫,避免使人產(chǎn)生誤解。
說明:較短的單詞可通過去掉“元音”形成縮寫;較長的單詞可取單詞的頭幾個字母形成縮寫;一些單詞有大家公認的縮寫。
示例:如下單詞的縮寫能夠被大家基本認可。
temp可縮寫為 tmp;
flag可縮寫為 flg;
statistic可縮寫為 stat;
increment可縮寫為 inc;
message可縮寫為 msg;
2 命名中若使用特殊約定或縮寫,則要有注釋說明。
說明:應(yīng)該在源文件的開始之處,對文件中所使用的縮寫或約定,特別是特殊的縮寫,進行必要的注釋說明。3 自己特有的命名風(fēng)格,要自始至終保持一致,不可來回變化。
說明:個人的命名風(fēng)格,在符合所在項目組或產(chǎn)品組的命名規(guī)則的前提下,才可使用。(即命名規(guī)則中沒有規(guī)定到的地方才可有個人命名風(fēng)格)。4 對于變量命名,禁止取單個字符(如i、j、k...),建議除了要有具體含義外,還能表明其變量類型、數(shù)據(jù)類型等,但i、j、k作局部循環(huán)變量是允許的。
5 命名規(guī)范采用小駝峰命名法
18 除非必要,不要用數(shù)字或較奇怪的字符來定義標識符。
19 除了編譯開關(guān)/頭文件等特殊應(yīng)用,應(yīng)避免使用
_EXAMPLE
、_TEST_
之類以下劃線開始和結(jié)尾的定義。
5 可讀性
- 1 注意運算符的優(yōu)先級,并用括號明確表達式的操作順序,避免使用默認優(yōu)先級。
表達式正確的寫法示例:
word = ( high << 8 ) | low;
if ( ( a | b ) && ( a & c ) )
if( ( a | b ) < ( c & d ) )
錯誤的寫法示例:
word = high << 8 | low;
if ( a | b && a & c )
if ( a | b < c & d ) /* 造成了判斷條件出錯 */
- 2 避免使用不易理解的數(shù)字,用有意義的標識來替代。涉及物理狀態(tài)或者含有物理意義的常量,不應(yīng)直接使用數(shù)字,必須用有意義的枚舉或宏來代替。
示例:如下的程序可讀性差。
if ( trunk[index].trunkState == 0 )<----不規(guī)范的寫法,應(yīng)使用有意義的標識
{
trunk[index].trunkState=1;<----不規(guī)范的寫法,應(yīng)使用有意義的標識.../*programcode*/
}
應(yīng)改為如下形式。
enum trunkState_e
{
TRUNK_IDLE=0,
TRUNK_BUSY=1
};
if ( trunk[index].trunkState == TRUNK_IDLE )
{
trunk[index].trunkState=TRUNK_BUSY;
//.../*programcode*/
}
- 3 不要使用難懂的技巧性很高的語句,除非很有必要時。
說明:高技巧語句不等于高效率的程序,實際上程序的效率關(guān)鍵在于算法。示例:如下表達式,考慮不周就可能出問題,也較難理解。
*stat_poi+++ = 1;
*++stat_poi += 1;
應(yīng)分別改為如下。
*stat_poi += 1;
stat_poi++; /* 此二語句功能相當(dāng)于 *stat_poi+++ = 1; */
++stat_poi;
*stat_poi += 1; /* 此二語句功能相當(dāng)于*++stat_poi += 1; */
6 變量、結(jié)構(gòu)、常量、宏
- 1 變量定義
變量按作用空間可以分為全局變量與局部變量(臨時變量)靜態(tài)變量,其空前前綴為g_,t_,s_;
變量按類型可以分為邏輯型、字符型、整型、長整型、字符串、浮點數(shù)、結(jié)構(gòu)類型、指針,其類型前綴為b,c,I,g,s,f,str,p。
規(guī)范要求
變量的命名采用空間前綴+類型前綴+駝峰法;舉例
uchar g_cMeterAddr; //全局變量,單字節(jié),表地址
uchar g_iTime; //全局變量,雙字節(jié),時間
uchar t_cLength; //局部變量,單字節(jié),長度
uchar g_bKeyInputOver; //全局變量,邏輯變量,鍵盤輸入結(jié)束
uchar g_sCommBuff[5]; //全局變量,字符串,通訊緩沖
uchar t_fValue; //局部變量,浮點數(shù),數(shù)據(jù)
uchar g_strDCBTbl; //全局變量,結(jié)構(gòu)類型,表
uchar* g_pCommBuff; //全局變量,指針,通訊緩沖
- (1) 為了方便書寫及記憶,變量類型需要采用類似如下重定義:
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long int uint32_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed long int int32_t;
#define __IO volatile
- (2) 常用類型與前綴
對于一些常見類型的變量,應(yīng)在其名字前標注表示其類型的前綴。前綴用小寫字母表示。前綴的使用請參照下列表格中說明
變量類型 | 前綴 | 舉例 |
---|---|---|
uint8_t | uc | ucSum |
int8_t | c | cSum |
uint16_t | us | usParaWord |
int16_t | s | sParaWord |
uint32_t | ul | ulParaWord |
int32_t | l | lParaWord |
uint8_t * | ucp | ucpWrite |
int8_t * | cp | cpWrite |
uint16_t* | usp | uspWrite |
int16_t* | sp | spWrite |
uint32_t * | ulp | ulpWrite |
int32_t * | lp | lpWrite |
uint8_t[] | uca | ucaNum[5] |
int8_t[] | ca | caNum[5] |
uint16_t[] | usa | usaNum[5] |
int16_t[] | sa | saNum[5] |
uint32_t[] | ula | ulaNum[5] |
int32_t[] | la | laNum[5] |
結(jié)構(gòu)體 | t | tPara |
- (3) 對于幾種變量類型組合,前綴可以迭加。
- 2 變量作用域的前綴
為了清晰的標識變量的作用域,減少發(fā)生命名沖突,應(yīng)該在變量類型前綴之前再加上表示變量作用域的前綴,并在變量類型前綴和變量作用域前綴之間用下劃線‘-’隔開。具體的規(guī)則如下:
- (1) 對于全局變量(global variable),在其名稱前加“g”和變量類型符號前綴。
uint32_t g_ulParaWord;
uint8_t g_ucByte;
- (2) 對于靜態(tài)變量(static variable),在其名稱前加“s”和變量類型符號前綴。
static uint32_t s_ulParaWord;
static uint8_t s_ucByte;
(3) 函數(shù)內(nèi)部等局部變量前不加作用域前綴。
(4) 對于常量,當(dāng)可能發(fā)生作用域和名字沖突問題時,以上幾條規(guī)則對于常量同樣適用。注意,雖然常量名的核心部分全部大寫,但此時常量的前綴仍然用小寫字母,以保持前綴的一致性。
3 對于結(jié)構(gòu)體命名類型,表示類型的名字,所有名字以小寫字母“tag”開頭,之后每個英文單詞的第一個字母大寫(包括第一個單詞的第一個字母),其他字母小寫,結(jié)尾_t標識。單詞之間不使用下劃線分隔,結(jié)構(gòu)體變量以t開頭。
/*結(jié)構(gòu)體命名類型名*/
typedef struct tagBillQuery_t
{
//...
}billQuery_t;
/*結(jié)構(gòu)體變量定義*/
billQuery_t tBillQuery;
- 4 對于枚舉定義全部采用大寫,結(jié)尾_e標識。
typedef enum
{
KB_F1=0, /* F1鍵代碼 */
KB_F2, /* F2鍵代碼 */
KB_F3 /* F3鍵代碼 */
}keyCODE_e;
- 5 常量、宏、模版的名字應(yīng)該全部大寫。如果這些名字由多個單詞組成,則單詞之間用下劃線分隔。宏指所有用宏形式定義的名字,包括常量類和函數(shù)類;常量也包括枚舉中的常量成員。
#define LOG_BUF_SIZE 8000
- 6 不推薦使用位域。
6 函數(shù)
- 1 函數(shù)的命名規(guī)則。每一個函數(shù)名前綴需包含模塊名,模塊名為小寫,與函數(shù)名區(qū)別開。
如:uartReceive(串口接收)
備注:對于非常簡單的程序,可以不加模塊名。
- 2 函數(shù)的的形參都以下劃線
a_
開頭,已示與普通變量進行區(qū)分。
/******************************************************************************
* 函數(shù)名:uartConvUartBaud
*功能:波特率轉(zhuǎn)換
* 輸入:_ulBaud:波特率
*輸出:無
* 返回:uint32-轉(zhuǎn)換后的波特率值
*/
uint32_t uartConvUartBaud( uint32_t a_ulBaud )
{
uint32_t ulBaud;
ulBaud = a_ulBaud * 2; /*計算波特率*/
//......
return ulBaud;
}
3 一個函數(shù)僅完成一件功能。
4 函數(shù)名應(yīng)準確描述函數(shù)的功能。避免使用無意義或含義不清的動詞為函數(shù)命名。使用動賓詞組為執(zhí)行某操作的函數(shù)命名。
說明:避免用含義不清的動詞如process、handle等為函數(shù)命名,因為這些動詞并沒有說明要具體做什么。
示例:參照如下方式命名函數(shù)。
void printRecord( uint32_t recInd );
int32_t inputRecord( void );
uint8_t getCurrentColor( void );
- 5 檢查函數(shù)所有參數(shù)輸入的有效性。
說明:如果約定由調(diào)用方檢查參數(shù)輸入,則應(yīng)使用assert()之類的宏,來驗證所有參數(shù)輸入的有效性。
-6 檢查函數(shù)所有非參數(shù)輸入的有效性,如數(shù)據(jù)文件、公共變量等。
說明:函數(shù)的輸入主要有兩種:一種是參數(shù)輸入;另一種是全局變量、數(shù)據(jù)文件的輸入,即非參數(shù)輸入。函數(shù)在使用輸入之前,應(yīng)進行必要的檢查。
- 7 防止將函數(shù)的參數(shù)作為工作變量。
說明:將函數(shù)的參數(shù)作為工作變量,有可能錯誤地改變參數(shù)內(nèi)容,所以很危險。對必須改變的參數(shù),最好先用局部變量代之,最后再將該局部變量的內(nèi)容賦給該參數(shù)。
- 8 避免設(shè)計五個以上參數(shù)函數(shù),不使用的參數(shù)從接口中去掉。
說明:目的減少函數(shù)間接口的復(fù)雜度,復(fù)雜的參數(shù)可以使用結(jié)構(gòu)傳遞。
- 9 在調(diào)用函數(shù)填寫參數(shù)時,應(yīng)盡量減少沒有必要的默認數(shù)據(jù)類型轉(zhuǎn)換或強制數(shù)據(jù)類型轉(zhuǎn)換。
說明:因為數(shù)據(jù)類型轉(zhuǎn)換或多或少存在危險。
- 10 避免使用BOOL參數(shù)。
說明:原因有二,其一是BOOL參數(shù)值無意義,TURE/FALSE的含義是非常模糊的,在調(diào)用時很難知道該參數(shù)到底傳達的是什么意思;其二是BOOL參數(shù)值不利于擴充。還有NULL也是一個無意義的單詞。
11 函數(shù)的返回值要清楚、明了。除非必要,最好不要把與函數(shù)返回值類型不同的變量,以編譯系統(tǒng)默認的轉(zhuǎn)換方式或強制的轉(zhuǎn)換方式作為返回值返回。
12 防止把沒有關(guān)聯(lián)的語句放到一個函數(shù)中。
說明:防止函數(shù)或過程內(nèi)出現(xiàn)隨機內(nèi)聚。隨機內(nèi)聚是指將沒有關(guān)聯(lián)或關(guān)聯(lián)很弱的語句放到同一個函數(shù)或過程中。隨機內(nèi)聚給函數(shù)或過程的維護、測試及以后的升級等造成了不便,同時也使函數(shù)或過程的功能不明確。使用隨機內(nèi)聚函數(shù),常常容易出現(xiàn)在一種應(yīng)用場合需要改進此函數(shù),而另一種應(yīng)用場合又不允許這種改進,從而陷入困境。在編程時,經(jīng)常遇到在不同函數(shù)中使用相同的代碼,許多開發(fā)人員都愿把這些代碼提出來,并構(gòu)成一個新函數(shù)。若這些代碼關(guān)聯(lián)較大并且是完成一個功能的,那么這種構(gòu)造是合理的,否則這種構(gòu)造將產(chǎn)生隨機內(nèi)聚的函數(shù)。示例:如下函數(shù)就是一種隨機內(nèi)聚。
void initVar( void )
{
rect.length = 0;
rect.width = 0; /*初始化矩形的長與寬*/
point.x = 10;
point.y = 10; /*初始化“點”的坐標*/
}
矩形的長、寬與點的坐標基本沒有任何關(guān)系,故以上函數(shù)是隨機內(nèi)聚。應(yīng)如下分為兩個函數(shù):
void initRect( void )
{
rect.length = 0;
rect.width = 0; /*初始化矩形的長與寬*/
}
void initPoint( void )
{
point.x = 10;
point.y = 10; /*初始化“點”的坐標*/
}
- 13 減少函數(shù)本身或函數(shù)間的遞歸調(diào)用。
說明:遞歸調(diào)用特別是函數(shù)間的遞歸調(diào)用(如A->B->C->A),影響程序的可理解性;遞歸調(diào)用一般都占用較多的系統(tǒng)資源(如棧空間);遞歸調(diào)用對程序的測試有一定影響。故除非為某些算法或功能的實現(xiàn)方便,應(yīng)減少沒必要的遞歸調(diào)用。
14 改進模塊中函數(shù)的結(jié)構(gòu),降低函數(shù)間的耦合度,并提高函數(shù)的獨立性以及代碼可讀性、效率和可維護性。優(yōu)化函數(shù)結(jié)構(gòu)時,要遵守以下原則:
(1) 能影響模塊功能的實現(xiàn)。
(2) 仔細考查模塊或函數(shù)出錯處理及模塊的性能要求并進行完善。
(3) 通過分解或合并函數(shù)來改進軟件結(jié)構(gòu)。
(4) 考查函數(shù)的規(guī)模,過大的要進行分解。
(5) 降低函數(shù)間接口的復(fù)雜度。
(6) 不同層次的函數(shù)調(diào)用要有較合理的扇入、扇出。
(7) 函數(shù)功能應(yīng)可預(yù)測。
(8) 提高函數(shù)內(nèi)聚。(單一功能的函數(shù)內(nèi)聚最高)
說明:對初步劃分后的函數(shù)結(jié)構(gòu)應(yīng)進行改進、優(yōu)化,使之更為合理。