示例:如下记录学生学习成绩的结构不合理。 typedef unsigned char _UC ; typedef unsigned int _UI ;
typedef struct _STUDENT_SCORE_STRU {
_UC szName[ 8 ] ; _UC cAge ; _UC cSex ; _UC cClass ; _UC cSubject ; float fScore ;
} _STUDENT_SCORE ;
因为每位学生都有多科学习成绩,故如上结构将占用较大空间。应如下改进(分为两个结构),总的存贮空间将变小,操作也变得更方便。 typedef struct _STUDENT_STRU {
_UC szName[ 8 ] ; _UC cAge ; _UC cSex ; _UC cClass ; } _STUDENT ;
typedef struct _STUDENT_SCORE_STRU {
_UI iStudentIndex ;
_UC cSubject ; float fScore ;
} _STUDENT_SCORE ;
<规则19> 循环体内工作量最小化。
应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的时间效率。
示例:如下代码效率不高。
for ( i= 0 ; i< MAX_ADD_NUMBER ; i++ ) {
nSum += i;
nBackSum = nSum ; /* 备份和 */ }
语句搉BackSum = nSum ;应该写在for语句之后,如下。 for ( i = 0 ; i < MAX_ADD_NUMBER ; i ++ ) {
nSum += i ; }
nBackSum = nSum ; /*备份和 */
<规则20> 在多重循环中,应将最忙的循环放在最内层。
<规则21> 避免循环体内含判断语句,将与循环变量无关的判断语句移到循环体外。 目的是减少判断次数。循环体中的判断语句是否可以移到循环体外,要视程序的具体情况而言,一般情况,与循环变量无关的判断语句可以移到循环体外,而有关的则不可以。 <规则22> 尽量用乘法或其它方法代替除法,特别是浮点运算中的除法,在时间效率要求不是特别严格时,要优先保证程序的可读性。 说明:浮点运算除法要占用较多CPU资源。
示例:如下表达式运算可能要占较多CPU资源。 #define PAI 3.1416
fRadius = fCircleLength / ( 2 * PAI ) ; 应如下把浮点除法改为浮点乘法。
#define PAI_RECIPROCAL ( 1 / 3.1416 ) // 编译器编译时,将生成具体浮点数 fRadius = fCircleLength * PAI_RECIPROCAL / 2 ; <规则23> 用“++\与\少用\
<规则24> 系统输入(如用户输入)、系统输出(如信息包输出)、系统资源操作(如内存分配、文件及目录操作)、网络操作(如通信、调用等)、任务之间的操作(如通信、调用等)时必须进行错误、超时或者异常处理。
<建议 1> 定义字符串变量的同时将其初始化为空即摂,以避免无限长字符串。 <建议 2> 在switch语句中将经常性的处理放在前面。 1.5 接口
<规则1> 头文件应采用 #ifndef / #define / #endif 的方式来防止多次被嵌入。 示例如下:
假设头文件为揇EF.INC\,则其内容应为: #ifndef __DEF_INC #define __DEF_INC ... #endif
<规则2> 去掉没有必要的公共变量,编程时应尽量少用公共变量。
公共变量是增大模块间耦合的原因之一,故应减少没必要的公共变量以降低模块间的耦合度。应该构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的公共变量,防止多个不同模块或函数都可以修改、创建同一公共变量的现象。 <规则3> 当向公共变量传递数据时,要防止越界现象发生。
对公共变量赋值时,若有必要应进行合法性检查,以提高代码的可靠性、稳定性。 <规则4> 返回值为指针的函数,不可将局部变量的地址作为返回值。
当函数退出时,非static局部变量将消失,所以引用返回的指针将可能引起严重后果。下例将不能完成正确的功能。 char *GetFilename(int nFileNo) {
char szFileName[20];
sprintf( szFileName, \ return szFileName; }
<规则5> 尽量不设计多参数函数,将不使用的参数从接口中去掉,降低接口复杂度。 减少函数间接口的复杂度。
<规则6> 对所调用函数的返回码要仔细、全面地处理。
防止把错误传递到后面的处理流程。如有意不检查其返回码,应明确指明。 如: (void)fclose(fp);
<规则7> 显示地给出函数的返回值类型。无返回值函数定义为void。 C、C++语言的编译系统默认无显示返回值函数的返回值类型为int。
<规则8> 声明函数原型时给出参数名称和类型,并且与实现此函数时的参数名称、类型保持一致,无参数的函数,用void声明。 示例:下面声明不正确。 int CheckData( ) ; int SetPoint( int, int ) ; int SetPoint( x, y ) int x, y;
应改为如下声明:
int CheckData( void ) ; int SetPoint( int x, int y ) ;
<规则9> 检查接口函数所有输入参数的有效性。
可直接检查或使用断言进行检查,尤其是指针参数。只在本模块内使用的函数可不检查。 <规则10> 检查函数的所有非参数输入,如数据文件、公共变量等。 可直接检查或使用断言进行检查,尤其是指针变量。
<规则11> 声明函数原型时,对于数组型参数,不要声明为指针,维护函数接口的清晰性。
示例:假设函数SortInt()完成的功能是对一组整数排序,接受的参数是一整数数组及数组中的元素个数,以下声明不符合规范。 void SortInt(int num, int *data); 应声明为:
void SortInt(int num, int data[]); 1.6 代码可测性
<规则1> 模块编写应该有完善的测试方面的考虑。
<规则2> 源代码中应该设计了代码测试的内容,如打印宏开关、变量值、函数名称、函数值等。
在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。
程序的调试与测试是软件生存周期中很重要的一个阶段,如何对软件进行较全面、高率的测试并尽可能地找出软件中的错误就成为很关键的问题。因此在编写源代码之前,除了要有一套比较完善的测试计划外,还应设计出一系列代码测试手段,为单元测试、集成测试及系统联调提供方便。
<规则3> 在同一项目组或产品组内,要有一套统一的为集成测试与系统联调准备的调测开关及相应打印函数,并且要有详细的说明。 本规则是针对项目组或产品组的。
示例: .ext文件示例,文件名为:EXAMPLE.EXT。