華為軟體編程規範學習(五)--變數、結構
5-1:去掉沒必要的公開變數
說明:公開變數是增大模組間耦合的原因之一,故應減少沒必要的公開變數以降低模組間的耦合度。
5-2:仔細定義並明確公開變數的含義、作用、取值範圍及公開變數間的關係
說明:在對變數聲明的同時,應對其含義、作用及取值範圍進行注釋說明,同時若有必要還應說明與其它變數的關係。
5-3:明確公開變數與操作此公開變數的函數或過程的關係,如訪問、修改及建立等
說明:明確過程操作變數的關係後,將有利於程式的進一步最佳化、單元測試、系統聯調以及代碼維護等。這種關係的說明可在注釋或文檔中描述。
樣本:在源檔案中,可按如下注釋形式說明。
RELATION System_Init Input_Rec Print_Rec Stat_Score
Student Create Modify Access Access
Score Create Modify Access Access, Modify
註:RELATION為操作關係;System_Init、Input_Rec、Print_Rec、Stat_Score為四個不同的函數;Student、Score為兩個全域變數;Create表示建立,Modify表示修改,Access表示訪問。
其中,函數Input_Rec、Stat_Score都可修改變數Score,故此變數將引起函數間較大的耦合,並可能增加代碼測試、維護的難度。
5-4:當向公開變數傳遞資料時,要十分小心,防止賦與不合理的值或越界等現象發生
說明:對公開變數賦值時,若有必要應進行合法性檢查,以提高代碼的可靠性、穩定性。
5-5:防止局部變數與公開變數同名
說明:若使用了較好的命名規則,那麼此問題可自動消除。
5-6:嚴禁使用未經初始化的變數作為右值
說明:特別是在C/C++中引用未經賦值的指標,經常會引起系統崩潰。
其他
5-1:構造僅有一個模組或函數可以修改、建立,而其餘有關模組或函數只訪問的公開變數,防止多個不同模組或函數都可以修改、建立同一公開變數的現象
說明:降低公開變數耦合度。
5-2:使用嚴格形式定義的、可移植的資料類型,盡量不要使用與具體硬體或軟體環境關係密切的變數
說明:使用標準的資料類型,有利於程式的移植。
樣本:如下例子(在DOS下BC3.1環境中),在移植時可能產生問題。
void main(){ register int index; // 寄存器變數 _AX = 0x4000; // _AX是BC3.1提供的寄存器“偽變數” ... // program code}
5-3:結構的功能要單一,是針對一種事務的抽象
說明:設計結構時應力爭使結構代表一種現實事務的抽象,而不是同時代表多種。結構中的各元素應代表同一事務的不同側面,而不應把描述沒有關係或關係很弱的不同事務的元素放到同一結構中。
樣本:如下結構不太清晰、合理。
typedef struct STUDENT_STRU{ unsigned char name[8]; /* student's name */ unsigned char age; /* student's age */ unsigned char sex; /* student's sex, as follows */ /* 0 - FEMALE; 1 - MALE */ unsigned char teacher_name[8]; /* the student teacher's name */ unisgned char teacher_sex; /* his teacher sex */} STUDENT;
若改為如下,可能更合理些。
typedef struct TEACHER_STRU{ unsigned char name[8]; /* teacher name */ unisgned char sex; /* teacher sex, as follows */ /* 0 - FEMALE; 1 - MALE */} TEACHER;typedef struct STUDENT_STRU{ unsigned char name[8]; /* student's name */ unsigned char age; /* student'sage */ unsigned char sex; /* student'ssex, as follows */ /* 0 - FEMALE; 1 - MALE */ unsigned int teacher_ind; /* his teacher index */} STUDENT;
5-4:不要設計面面俱到、非常靈活的資料結構
說明:面面俱到、靈活的資料結構反而容易引起誤解和操作困難。
5-5:不同結構間的關係不要過於複雜
說明:若兩個結構間關係較複雜、密切,那麼應合為一個結構。
樣本:如下兩個結構的構造不合理。
typedef struct PERSON_ONE_STRU{ unsigned char name[8]; unsigned char addr[40]; unsigned char sex; unsigned char city[15];} PERSON_ONE;typedef struct PERSON_TWO_STRU{ unsigned char name[8]; unsigned char age; unsigned char tel;} PERSON_TWO;
由於兩個結構都是描述同一事物的,那麼不如合成一個結構。
typedef struct PERSON_STRU{ unsigned char name[8]; unsigned char age; unsignedchar sex; unsigned char addr[40]; unsigned char city[15]; unsigned char tel;} PERSON;
5-6:結構中元素的個數應適中。若結構中元素個數過多可考慮依據某種原則把元素組成不同的子結構,以減少原結構中元素的個數
說明:增加結構的可理解性、可操作性和可維護性。
樣本:假如認為如上的_PERSON結構元素過多,那麼可如下對之劃分。
typedef struct PERSON_BASE_INFO_STRU{ unsigned char name[8]; unsigned char age; unsigned char sex;} PERSON_BASE_INFO;typedef struct PERSON_ADDRESS_STRU{ unsigned char addr[40]; unsigned char city[15]; unsigned char tel;} PERSON_ADDRESS;typedef struct PERSON_STRU{ PERSON_BASE_INFO person_base; PERSON_ADDRESS person_addr;} PERSON;
5-7:仔細設計結構中元素的布局與排列順序,使結構容易理解、節省佔用空間,並減少引起誤用現象
說明:合理排列結構中元素順序,可節省空間的並增加可理解性。
樣本:如下結構中的位域排列,將佔較大空間,可讀性也稍差。
typedef struct EXAMPLE_STRU{ unsigned int valid: 1; PERSON person; unsigned int set_flg: 1;} EXAMPLE;
若改成如下形式,不僅可節省1位元組空間,可讀性也變好了。
typedef structEXAMPLE_STRU{ unsigned int valid: 1; unsigned int set_flg: 1; PERSON person ;} EXAMPLE;
5-8:結構的設計要盡量考慮向前相容和以後的版本升級,並為某些未來可能的應用保留餘地(如預留一些空間等)
說明:軟體向前相容的特性,是軟體產品是否成功的重要標誌之一。如果要想使產品具有較好的前向相容,那麼在產品設計之初就應為以後版本升級保留一定餘地,並且在產品升級時必須考慮前一版本的各種特性。
5-9:留心具體語言及編譯器處理不同資料類型的原則及有關細節
說明:如在C語言中,static局部變數將在記憶體“資料區”中產生,而非static局部變數將在“堆棧”中產生。這些細節對程式品質的保證非常重要。
5-10:編程時,要注意資料類型的強制轉換
說明:當進行資料類型強制轉換時,其資料的意義、轉換後的取值等都有可能發生變化,而這些細節若考慮不周,就很有可能留下隱患。
5-11:對編譯系統預設的資料類型轉換,也要有充分的認識
樣本:如下賦值,多數編譯器不產生警示,但值的含義還是稍有變化。
char chr;unsigned short intexam;chr = -1;exam = chr; // 編譯器不產生警示,此時exam為0xFFFF。
5-12:盡量減少沒有必要的資料類型預設轉換與強制轉換
5-13:合理地設計資料並使用自訂資料類型,避免資料間進行不必要的類型轉換
5-14:對自訂資料類型進行恰當命名,使它成為自描述性的,以提高代碼可讀性。注意其命名方式在同一產品中的統一
說明:使用自訂類型,可以彌補程式設計語言提供類型少、資訊量不足的缺點,並能使程式清晰、簡潔。
樣本:可參考如下方式聲明自訂資料類型。
下面的聲明可使資料類型的使用簡潔、明了。
typedef unsigned char BYTE;typedef unsigned short WORD;typedef unsigned int DWORD;
下面的聲明可使資料類型具有更豐富的含義。
typedef float DISTANCE;typedef float SCORE;
5-15:當聲明用於分布式環境或不同CPU間通訊環境的資料結構時,必須考慮機器的位元組順序、使用的位域及位元組對齊等問題
說明:比如IntelCPU與68360CPU,在處理位域及整數時,其在記憶體存放的“順序”正好相反。
樣本:假如有如下短整數及結構。
unsigned short intexam;typedef struct EXAM_BIT_STRU{ /* Intel 68360 */ unsigned int A1: 1; /* bit 0 7 */ unsigned int A2: 1; /* bit 1 6 */ unsigned int A3: 1; /* bit 2 5 */} EXAM_BIT;
如下是IntelCPU產生短整數及位域的方式。
記憶體:0 1 2 ... (從低到高,以位元組為單位)
exam exam低位元組 exam高位元組
記憶體: 0 bit 1bit 2 bit ... (位元組的各“位”)
EXAM_BIT A1 A2 A3
如下是68360CPU產生短整數及位域的方式。
記憶體:0 1 2 ... (從低到高,以位元組為單位)
exam exam高位元組 exam低位元組
記憶體: 7 bit 6bit 5 bit ... (位元組的各“位”)
EXAM_BIT A1 A2 A3
說明:在對齊下,CPU的運行效率要快得多。
樣本:如,當一個long型數(中long1)在記憶體中的位置正好與記憶體的字邊界對齊時,CPU存取這個數只需訪問一次記憶體,而當一個long型數(中的long2)在記憶體中的位置跨越了字邊界時,CPU存取這個數就需要多次訪問記憶體,如i960cx訪問這樣的數需讀記憶體三次(一個BYTE、一個SHORT、一個BYTE,由CPU的微代碼執行,對軟體透明),所有對齊下CPU的運行效率明顯快多了。
1 8 16 24 32
------- ------- ------- -------
| long1 | long1 | long1 | long1 |
------- ------- ------- -------
| | | | long2 |
------- ------- ------- --------
| long2 | long2 | long2 | |
------- ------- ------- --------
| ....