中国高校课件下载中心 》 教学资源 》 大学文库

《计算机程序设计基础》课程学习指南(C语言)C语言初学者编程规范-2/2

文档信息
资源类别:文库
文档格式:PDF
文档页数:10
文件大小:384.94KB
团购合买:点击进入团购
内容简介
《计算机程序设计基础》课程学习指南(C语言)C语言初学者编程规范-2/2
刷新页面文档预览

C语言初学者编程规范-23.4函数的命名规范(1)函数的命名应该尽量用英文(或英文缩写、中文全拼、中文全拼缩写)表达出函数完成的功能一一函数名应准确描述函数的功能。遵循动宾结构的命名法则,函数名中动词在前,并在命名前加入函数的前缀,函数名的长度不得少于8个字母。函数名首字大写,若包含有两个单词的每个单词首字母大写。如果是OOP方法,可以只有动词(名词是对象本身)。示例:LONGGetDeviceCount(......);void print_record(unsigned int rec_ind);int input_record(void ) ;unsigned char get_current_color(void);(2)避免使用无意义或含义不清的动词为函数命名。如使用process、handle等为函数命名,因为这些动词并没有说明要具体做什么。(3)必须使用函数原型声明。函数原型声明包括:引用外来函数及内部函数,外部引用必须在右侧注明函数来源:模块名及文件名;内部函数,只要注释其定义文件名一一和调用者在同一文件中(简单程序)时不需要注释。应确保每个函数声明中的参数的名称、类型和定义中的名称、类型一致。3.5函数参数命名规范(1)参数名称的命名参照变量命名规范。2)为了提高程序的运行效率,减少参数占用的堆栈,传递大结构的参数,一律采用指针或引用方式传递。(3)为了便于其他程序员识别某个指针参数是入口参数还是出口参数,同时便于编译器检查错误,应该在入口参数前加入const标志。如:......cmCopyString(constCHAR*c_szSource,CHAR*szDest)3.6文件名(包括动态库、组件、控件、工程文件等)的命名规范文件名的命名要求表达出文件的内容,要求文件名的长度不得少于5个字母,严禁使用象file1,myfile之类的文件名。4可读性4.1避免使用默认的运算优先级注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级,可防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。示例:下列语句中的表达式word = (high << 8) / low (1)if (a|b) && (a&c)) (2)if ((ab) <(c&d))(3)如果书写为:high<<8/lowab&&a&ca|b<c&d由于high << 8 / low =(high << 8) / lowa/b&&a&c=(a/b)&&(a&c),(1)(2)不会出错,但语句不易理解;

C语言初学者编程规范-2 3.4 函数的命名规范 (1)函数的命名应该尽量用英文(或英文缩写、中文全拼、中文全拼缩写)表达出函数完成的功能——函 数名应准确描述函数的功能。遵循动宾结构的命名法则,函数名中动词在前,并在命名前加入函数的 前缀,函数名的长度不得少于8个字母。函数名首字大写,若包含有两个单词的每个单词首字母大 写。如果是OOP 方法,可以只有动词(名词是对象本身)。示例: LONG GetDeviceCount(.); void print_record( unsigned int rec_ind ) ; int input_record( void ) ; unsigned char get_current_color( void ) ; (2)避免使用无意义或含义不清的动词为函数命名。如使用process、handle等为函数命名,因为这些 动词并没有说明要具体做什么。 (3)必须使用函数原型声明。函数原型声明包括:引用外来函数及内部函数,外部引用必须在右侧注 明函数来源:模块名及文件名;内部函数,只要注释其定义文件名——和调用者在同一文件中(简单 程序)时不需要注释。 应确保每个函数声明中的参数的名称、类型和定义中的名称、类型一致。 3.5 函数参数命名规范 (1)参数名称的命名参照变量命名规范。 (2)为了提高程序的运行效率,减少参数占用的堆栈,传递大结构的参数,一律采用指针或引用方式 传递。 (3)为了便于其他程序员识别某个指针参数是入口参数还是出口参数,同时便于编译器检查错误,应 该在入口参数前加入const标志。如: .cmCopyString(const CHAR * c_szSource, CHAR * szDest) 3.6 文件名(包括动态库、组件、控件、工程文件等)的命名规范 文件名的命名要求表达出文件的内容,要求文件名的长度不得少于5个字母,严禁使用象file1,myfile 之类的文件名。 4 可读性 4.1 避免使用默认的运算优先级 注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级,可防止阅读程序时 产生误解,防止因默认的优先级与设计思想不符而导致程序出错。 示例:下列语句中的表达式 word = (high << 8) | low (1) if ((a | b) && (a & c)) (2) if ((a | b) < (c & d)) (3) 如果书写为: high << 8 | low a | b && a & c a | b < c & d 由于 high << 8 | low = ( high << 8) | low, a | b && a & c = (a | b) && (a & c), (1)(2)不会出错,但语句不易理解;

ab<c&d=al(b<c)&d,(3)造成了判断条件出错。4.2使用有意义的标识,避免直接使用数字避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的枚举或宏来代替。示例:如下的程序可读性差。if (Trunk[index].trunk_state == 0)1Trunk[index].trunk_state = 1;.../l programcode7应改为如下形式。#defineTRUNK_IDLE0#defineTRUNKBUSY1if (Trunk[index].trunk_state ==TRUNK_IDLE)1Trunk[index].trunk_state = TRUNK_BUSY;.../l programcode74.3源程序中关系较为紧密的代码应尽可能相邻这样做的好处是便于程序阅读和查找。示例:以下代码布局不太合理。rect.length=10;char_poi=str;rect.width = 5;若按如下形式书写,可能更清晰一些。rect.length = 10;rect.width=5;II矩形的长与宽关系较密切,放在一起。char_poi= str;4.4不要使用难懂的技巧性很高的语句、复杂的表达式除非很有必要时,原则上不要使用难懂的技巧性很高的语句和复杂的表达式一一高技巧语句不等于高效率的程序,源程序占用空间的节约并不等于目标程序占用空间的节约,实际上程序的效率关键在于算法。(1)如下表达式,考虑不周就可能出问题,也较难理解。* stat_poi ++ += 1;* ++ stat_poi += 1;应分别改为如下:*stat_poi += 1;stat_poi++;Il此二语句功能相当于"*stat_poi+++=1;"++ stat_poi;*stat_poi+=1;I此二语句功能相当于"*++stat_poi+=1;"(2)如下表达式,不同的编译器给出的结果不一样,b[是否先执行?x=b + i++;应改为:x = bi + i;i++;5变量与结构

a | b < c & d = a | (b < c) & d,(3)造成了判断条件出错。 4.2 使用有意义的标识,避免直接使用数字 避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应 直接使用数字,必须用有意义的枚举或宏来代替。 示例:如下的程序可读性差。 if (Trunk[index].trunk_state == 0) { Trunk[index].trunk_state = 1; . // program code } 应改为如下形式。 #define TRUNK_IDLE 0 #define TRUNK_BUSY 1 if (Trunk[index].trunk_state == TRUNK_IDLE) { Trunk[index].trunk_state = TRUNK_BUSY; . // program code } 4.3 源程序中关系较为紧密的代码应尽可能相邻 这样做的好处是便于程序阅读和查找。示例:以下代码布局不太合理。 rect.length = 10; char_poi = str; rect.width = 5; 若按如下形式书写,可能更清晰一些。 rect.length = 10; rect.width = 5; // 矩形的长与宽关系较密切,放在一起。 char_poi = str; 4.4 不要使用难懂的技巧性很高的语句、复杂的表达式 除非很有必要时,原则上不要使用难懂的技巧性很高的语句和复杂的表达式——高技巧语句不等于 高效率的程序,源程序占用空间的节约并不等于目标程序占用空间的节约,实际上程序的效率关键 在于算法。 (1)如下表达式,考虑不周就可能出问题,也较难理解。 * stat_poi ++ += 1; * ++ stat_poi += 1; 应分别改为如下: *stat_poi += 1; stat_poi++; // 此二语句功能相当于" * stat_poi ++ += 1; " ++ stat_poi; *stat_poi += 1; // 此二语句功能相当于" * ++ stat_poi += 1; " (2)如下表达式,不同的编译器给出的结果不一样,b[i]是否先执行? x=b[i] + i++; 应改为: x = b[i] + i; i++; 5 变量与结构

5.1谨慎使用全局(公共)变量(1)去掉没必要的公共变量。公共变量是增大模块间耦合的原因之一,故应减少没必要的公共变量以降低模块间的耦合度。(2)仔细定义并明确公共变量的含义、作用、取值范围及公共变量间的关系。在对变量声明的同时,应对其含义、作用及取值范围进行注释说明,同时若有必要还应说明与其它变量的关系。(3)防止局部变量与公共变量同名一一通过使用较好的命名规则来消除此问题。5.2数据类型间的转换(1)编程时,要注意数据类型的强制转换。当进行数据类型强制转换时,其数据的意义、转换后的取值等都有可能发生变化,而这些细节若考虑不周,就很有可能留下隐患。(2)对编译系统默认的数据类型转换,也要有充分的认识。示例:如下赋值,多数编译器不产生告警,但值的含义还是稍有变化char chr;unsigned short int exam;chr = -1;exam=chr;l编译器不产生告警,此时exam为0xFFFF。(3)尽量减少没有必要的数据类型默认转换与强制转换。例如,所有的unsigned类型都应该有后缀"U"以明确其类型。(4)合理地设计数据并使用自定义数据类型,避免数据间进行不必要的类型转换。(5)对自定义数据类型进行恰当命名,使它成为自描述性的,以提高代码可读性。注意其命名方式在同一产品中的统一,并且保证没有多重定义。使用自定义类型,可以弥补编程语言提供类型少、信息量不足的缺点,并能使程序清晰、简洁。示例:可参考如下方式声明自定义数据类型。下面的声明可使数据类型的使用简洁、明了。typedefunsignedcharBYTEtypedefunsigned short WORD;typedefunsigned int DWORD下面的声明可使数据类型具有更丰富的含义。typedeffloatDISTANCE;typedeffloatSCORE(6)不要用八进制数一一整型常数以0"开始会被认为是8进制。示例:code[1]=109code[2]=100code[3]=052code[4]=071如果是对总线消息初始化,会有危险。6函数与过程6.1函数的功能与规模设计(1)函数应当短而精美,而且只做一件事。不要设计多用途面面俱到的函数,多功能集于一身的函数,很可能使函数的理解、测试、维护等变得困难。一个函数应最多占满1或2个屏幕(就象我们知道的那样,ISO/ANSI的屏幕大小是80X24),只做一件事并且把它做好。一个函数的最大长度与它的复杂度和缩进级别成反比。所以,如果如果你有一个概念上简单(案,“简单"是simple而不是easy)的函数,它恰恰包含着一个很长的case语句,这样你不得不为不同的情况准备不懂的处理,那么这样的长函数是没问题的。然而,如果你有一个复杂的函数,你猜想一个并非天才的高一学生可能看不懂得这个函数,你就应当努力把它减缩得更接近前面提到的最大函数长度限制。可以使用一些辅助函数,给它们取描述性

5.1 谨慎使用全局(公共)变量 (1)去掉没必要的公共变量。公共变量是增大模块间耦合的原因之一,故应减少没必要的公共变量以 降低模块间的耦合度。 (2)仔细定义并明确公共变量的含义、作用、取值范围及公共变量间的关系。在对变量声明的同时, 应对其含义、作用及取值范围进行注释说明,同时若有必要还应说明与其它变量的关系。 (3)防止局部变量与公共变量同名——通过使用较好的命名规则来消除此问题。 5.2 数据类型间的转换 (1)编程时,要注意数据类型的强制转换。当进行数据类型强制转换时,其数据的意义、转换后的取 值等都有可能发生变化,而这些细节若考虑不周,就很有可能留下隐患。 (2)对编译系统默认的数据类型转换,也要有充分的认识。示例:如下赋值,多数编译器不产生告 警,但值的含义还是稍有变化。 char chr; unsigned short int exam; chr = -1; exam = chr; // 编译器不产生告警,此时exam为0xFFFF。 (3)尽量减少没有必要的数据类型默认转换与强制转换。例如,所有的 unsigned类型都应该有后 缀"U"以明确其类型。 (4)合理地设计数据并使用自定义数据类型,避免数据间进行不必要的类型转换。 (5)对自定义数据类型进行恰当命名,使它成为自描述性的,以提高代码可读性。注意其命名方式在 同一产品中的统一,并且保证没有多重定义。使用自定义类型,可以弥补编程语言提供类型少、信 息量不足的缺点,并能使程序清晰、简洁。示例:可参考如下方式声明自定义数据类型。 下面的声明可使数据类型的使用简洁、明了。 typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; 下面的声明可使数据类型具有更丰富的含义。 typedef float DISTANCE; typedef float SCORE; (6)不要用八进制数——整型常数以"0"开始会被认为是8进制。示例: code[1]=109 code[2]=100 code[3]=052 code[4]=071 如果是对总线消息初始化,会有危险。 6 函数与过程 6.1 函数的功能与规模设计 (1)函数应当短而精美,而且只做一件事。不要设计多用途面面俱到的函数,多功能集于一身的函 数,很可能使函数的理解、测试、维护等变得困难。一个函数应最多占满1或2个屏幕(就象我们知道 的那样,ISO/ANSI的屏幕大小是80X24),只做一件事并且把它做好。 一个函数的最大长度与它的复杂度和缩进级别成反比。所以,如果如果你有一个概念上简单(案,"简 单"是simple而不是easy)的函数,它恰恰包含着一个很长的case语句,这样你不得不为不同的情况准 备不懂的处理,那么这样的长函数是没问题的。 然而,如果你有一个复杂的函数,你猜想一个并非天才的高一学生可能看不懂得这个函数,你就应 当努力把它减缩得更接近前面提到的最大函数长度限制。可以使用一些辅助函数,给它们取描述性

的名字(如果你认为这些辅助函数的调用是性能关键的,可以让编译器把它们内联进来,这比在单个函数内完成所有的事情通常要好些)。对函数还存在另一个测量标准:局部变量的数目。这不该超过5到10个,否则你可能会弄错。应当重新考虑这个函数,把它分解成小片。人类的大脑一般能同时记住7个不同的东西,超过这个数目就会犯糊涂。或许你认为自己很聪明,那么请你理解一下从现在开始的2周时间你都做什么了。(2)为简单功能编写函数。虽然为仅用一两行就可完成的功能去编函数好象没有必要,但用函数可使功能明确化,增加程序可读性,亦可方便维护、测试。示例:如下语句的功能不很明显。value=(a>b)?a:b:改为如下就很清晰了。int max (int a, int b)1return((a>b)?a:b)}value =max (a, b);或改为如下。#define MAX (a, b) ((a) > (b) ? (a) : (b))value=MAx(a,b)当一个过程(函数)中对较长变量(一般是结构的成员)有较多引用时,可以用一个意义相当的宏代替-这样可以增加编程效率和程序的可读性。示例:在某过程中较多引用TheReceiveBuffer[FirstSocket].byDataPtr,则可以通过以下宏定义来代替:#definepSOCKDATATheReceiveBuffer[FirstScoket].byDataPtr(3)防止把没有关联的语句放到一个函数中,防止函数或过程内出现随机内聚。随机内聚是指将没有关联或关联很弱的语句放到同一个函数或过程中。随机内聚给函数或过程的维护、测试及以后的升级等造成了不便,同时也使函数或过程的功能不明确。使用随机内聚函数,常常容易出现在一种应用场合需要改进此函数,而另一种应用场合又不允许这种改进,从而陷入困境在编程时,经常遇到在不同函数中使用相同的代码,许多开发人员都愿把这些代码提出来,并构成一个新函数。若这些代码关联较大并且是完成一个功能的,那么这种构造是合理的,否则这种构造将产生随机内聚的函数。示例:如下函数就是一种随机内聚。void Init Var(void)1Rect.length = 0;Rect.width=O;/*初始化矩形的长与宽*Point.x = 10;Point.y=10;/*初始化"点"的坐标*1矩形的长、宽与点的坐标基本没有任何关系,故以上函数是随机内聚。应如下分为两个函数:voidInitRect(void)1Rect.length = 0O;Rect.width=O;*初始化矩形的长与宽*1void Init_Point(void)1Point.x = 10;

的名字(如果你认为这些辅助函数的调用是性能关键的,可以让编译器把它们内联进来,这比在单个 函数内完成所有的事情通常要好些)。 对函数还存在另一个测量标准:局部变量的数目。这不该超过5到10个,否则你可能会弄错。应当重 新考虑这个函数,把它分解成小片。人类的大脑一般能同时记住7个不同的东西,超过这个数目就会 犯糊涂。或许你认为自己很聪明,那么请你理解一下从现在开始的2周时间你都做什么了。 (2)为简单功能编写函数。虽然为仅用一两行就可完成的功能去编函数好象没有必要,但用函数可使 功能明确化,增加程序可读性,亦可方便维护、测试。示例:如下语句的功能不很明显。 value = ( a > b ) ? a : b ; 改为如下就很清晰了。 int max (int a, int b) { return ((a > b) ? a : b); } value = max (a, b); 或改为如下。 #define MAX (a, b) (((a) > (b)) ? (a) : (b)) value = MAX (a, b); 当一个过程(函数)中对较长变量(一般是结构的成员)有较多引用时,可以用一个意义相当的宏代替 ——这样可以增加编程效率和程序的可读性。示例:在某过程中较多引用 TheReceiveBuffer[FirstSocket].byDataPtr,则可以通过以下宏定义来代替: # define pSOCKDATA TheReceiveBuffer[FirstScoket].byDataPtr (3)防止把没有关联的语句放到一个函数中,防止函数或过程内出现随机内聚。随机内聚是指将没有 关联或关联很弱的语句放到同一个函数或过程中。随机内聚给函数或过程的维护、测试及以后的升 级等造成了不便,同时也使函数或过程的功能不明确。使用随机内聚函数,常常容易出现在一种应 用场合需要改进此函数,而另一种应用场合又不允许这种改进,从而陷入困境。 在编程时,经常遇到在不同函数中使用相同的代码,许多开发人员都愿把这些代码提出来,并构成 一个新函数。若这些代码关联较大并且是完成一个功能的,那么这种构造是合理的,否则这种构造 将产生随机内聚的函数。 示例:如下函数就是一种随机内聚。 void Init_Var( void ) { Rect.length = 0; Rect.width = 0; /* 初始化矩形的长与宽 */ Point.x = 10; Point.y = 10; /* 初始化"点"的坐标 */ } 矩形的长、宽与点的坐标基本没有任何关系,故以上函数是随机内聚。 应如下分为两个函数: void Init_Rect( void ) { Rect.length = 0; Rect.width = 0; /* 初始化矩形的长与宽 */ } void Init_Point( void ) { Point.x = 10;

Point.y=10;*初始化"点"的坐标*7(4)如果多段代码重复做同一件事情,那么在函数的划分上可能存在问题。若此段代码各语句之间有实质性关联并且是完成同一件功能的,那么可考虑把此段代码构造成一个新的函数。(5)减少函数本身或函数间的递归调用。递归调用特别是函数间的递归调用(如A->B->C->A),影响程序的可理解性;递归调用一般都占用较多的系统资源(如栈空间);递归调用对程序的测试有一定影响。故除非为某些算法或功能的实现方便,应减少没必要的递归调用,对于safe-related系统不能用递归,因为超出堆栈空间很危险。6.2函数的返回值(1)对于函数的返回位置,尽量保持单一性,即一个函数尽量做到只有一个返回位置。(单入口单出口)。要求大家统一函数的返回值,所有的函数的返回值都将以编码的方式返回。例如编码定义如下:#defineCM_POINT_IS_NULLCMMAKEHR(OX200)::建议函数实现如下:LONG函数名(参数....1LONGIResult;I/保持错误号IResult=CM_OK;1如果参数有错误则返回错误号if(参数==NULL)1IResult=CM_POINT_IS_NULL;goto END;人ENDreturnIResult:7(2)除非必要,最好不要把与函数返回值类型不同的变量,以编译系统默认的转换方式或强制的转换方式作为返回值返回。(3)函数的返回值要清楚、明了,让使用者不容易忽视错误情况。函数的每种出错返回值的意义要清晰、明了、准确,防止使用者误用、理解错误或忽视错误返回码。4)函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的输出。带有内部存储器"的函数的功能可能是不可预测的,因为它的输出可能取决于内部存储器(如某标记)的状态。这样的函数既不易于理解又不利于测试和维护。在C/C++语言中,函数的static局部变量是函数的内部存储器,有可能使函数的功能不可预测,然而,当某函数的返回值为指针类型时,则必须是STATIC的局部变量的地址作为返回值,若为AUTO类,则返回为错针。示例:如下函数,其返回值(即功能)是不可预测的。unsignedintintegersum(unsignedintbase)1unsigned int index;staticunsignedintsum=O;Il注意,是static类型的I若改为auto类型,则函数即变为可预测。for(index=1;index<=base;index++)1sum += index;

Point.y = 10; /* 初始化"点"的坐标 */ } (4)如果多段代码重复做同一件事情,那么在函数的划分上可能存在问题。若此段代码各语句之间有 实质性关联并且是完成同一件功能的,那么可考虑把此段代码构造成一个新的函数。 (5)减少函数本身或函数间的递归调用。递归调用特别是函数间的递归调用(如A->B->C->A),影响程 序的可理解性;递归调用一般都占用较多的系统资源(如栈空间);递归调用对程序的测试有一定影 响。故除非为某些算法或功能的实现方便,应减少没必要的递归调用,对于safe-related 系统不能用 递归,因为超出堆栈空间很危险。 6.2 函数的返回值 (1)对于函数的返回位置,尽量保持单一性,即一个函数尽量做到只有一个返回位置。(单入口单出 口)。 要求大家统一函数的返回值,所有的函数的返回值都将以编码的方式返回。 例如编码定义如下: #define CM_POINT_IS_NULL CMMAKEHR(0X200) : : 建议函数实现如下: LONG 函数名(参数,.) { LONG lResult; //保持错误号 lResult=CM_OK; //如果参数有错误则返回错误号 if(参数==NULL) { lResult=CM_POINT_IS_NULL; goto END; } . END: return lResult; } (2)除非必要,最好不要把与函数返回值类型不同的变量,以编译系统默认的转换方式或强制的转换 方式作为返回值返回。 (3)函数的返回值要清楚、明了,让使用者不容易忽视错误情况。函数的每种出错返回值的意义要清 晰、明了、准确,防止使用者误用、理解错误或忽视错误返回码。 (4)函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的输出。带有内部"存储 器"的函数的功能可能是不可预测的,因为它的输出可能取决于内部存储器(如某标记)的状态。这样 的函数既不易于理解又不利于测试和维护。在C/C++语言中,函数的static局部变量是函数的内部存 储器,有可能使函数的功能不可预测,然而,当某函数的返回值为指针类型时,则必须是STATIC的 局部变量的地址作为返回值,若为AUTO类,则返回为错针。 示例:如下函数,其返回值(即功能)是不可预测的。 unsigned int integer_sum( unsigned int base ) { unsigned int index; static unsigned int sum = 0; // 注意,是static类型的。 // 若改为auto类型,则函数即变为可预测。 for (index = 1; index <= base; index++) { sum += index;

1return sum;16.3函数参数(1)只当你确实需要时才用全局变量,函数间应尽可能使用参数、返回值传递消息。(2)防止将函数的参数作为工作变量。将函数的参数作为工作变量,有可能错误地改变参数内容,所以很危险。对必须改变的参数,最好先用局部变量代之,最后再将该局部变量的内容赋给该参数。示例:下函数的实现不太好。void sum_data( unsigned int num, int *data, int *sum )unsigned int count;*sum=0;for(count=O;count<num;count++)1*sum+=data[count];I/sum成了工作变量,不太好。77若改为如下,则更好些void sum_data( unsigned int num, int *data, int *sum )unsigned int count ;intsum temp;sum_temp =0;for(count=O;count<num;count++)sum_temp += data[count];1*sum= sum_temp;子7效率(1)编程时要经常注意代码的效率。代码效率分为全局效率、局部效率、时间效率及空间效率。全局效率是站在整个系统的角度上的系统效率;局部效率是站在模块或函数角度上的效率;时间效率是程序处理输入任务所需的时间长短;空间效率是程序所需内存空间,如机器代码空间大小、数据空间大小、栈空间大小等(2)在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码效率。不能一味地追求代码效率,而对软件的正确性、稳定性、可读性及可测性造成影响。(3)局部效率应为全局效率服务,不能因为提高局部效率而对全局效率造成影响。(4)循环体内工作量最小化。应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的时间效率。示例:如下代码效率不高。for(ind=O;ind<MAXADD_NUMBER;ind++)Lsum += ind;back_sum=sum;/*backupsum*7

} return sum; } 6.3 函数参数 (1)只当你确实需要时才用全局变量,函数间应尽可能使用参数、返回值传递消息。 (2)防止将函数的参数作为工作变量。将函数的参数作为工作变量,有可能错误地改变参数内容,所 以很危险。对必须改变的参数,最好先用局部变量代之,最后再将该局部变量的内容赋给该参数。 示例:下函数的实现不太好。 void sum_data( unsigned int num, int *data, int *sum ) { unsigned int count; *sum = 0; for (count = 0; count < num; count++) { *sum += data[count]; // sum成了工作变量,不太好。 } } 若改为如下,则更好些。 void sum_data( unsigned int num, int *data, int *sum ) { unsigned int count ; int sum_temp; sum_temp = 0; for (count = 0; count < num; count ++) { sum_temp += data[count]; } *sum = sum_temp; } 7 效率 (1)编程时要经常注意代码的效率。代码效率分为全局效率、局部效率、时间效率及空间效率。全局 效率是站在整个系统的角度上的系统效率;局部效率是站在模块或函数角度上的效率;时间效率是 程序处理输入任务所需的时间长短;空间效率是程序所需内存空间,如机器代码空间大小、数据空 间大小、栈空间大小等。 (2)在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码效率。不能一味地追求 代码效率,而对软件的正确性、稳定性、可读性及可测性造成影响。 (3)局部效率应为全局效率服务,不能因为提高局部效率而对全局效率造成影响。 (4)循环体内工作量最小化。应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作 量最小,从而提高程序的时间效率。 示例:如下代码效率不高。 for (ind = 0; ind < MAX_ADD_NUMBER; ind++) { sum += ind; back_sum = sum; /* backup sum */ }

语句backsum=sum;完全可以放在for语句之后,如下。for (ind = O; ind < MAX_ADD_NUMBER; ind++)Tsum += ind;7backsum=sum;/*backupsum*/(5)不应花过多的时间拼命地提高调用不很频繁的函数代码效率。对代码优化可提高效率,但若考虑不周很有可能引起严重后果。(6)在多重循环中,应将最忙的循环放在最内层,以减少CPU切入循环层的次数。示例:如下代码效率不高。for (row=0; row<100; row++)1for (col = 0; col < 5; col++){sum += a[row][col];71可以改为如下方式,以提高效率。for (col = 0; col < 5; col++)1for (row = 0; row< 100; row++)1sum+=a[row][col]11(7)尽量减少循环嵌套层次。(8)避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中。目的是减少判断次数。循环体中的判断语句是否可以移到循环体外,要视程序的具体情况而言,一般情况,与循环变量无关的判断语句可以移到循环体外,而有关的则不可以。示例:如下代码效率稍低。for (ind = O; ind < MAX_RECT_NUMBER; ind++)1if (data_type==RECT_AREA)1area sum+=rect area[ind];Jelserect_length_sum += rect[ind].length;rect_width_sum += rect[ind].width;7因为判断语句与循环变量无关,故可如下改进,以减少判断次数。if (data_type==RECT_AREA)1for (ind = 0; ind < MAX_RECT_NUMBER; ind++)1area_sum += rect_area[ind];1Jelse1for(ind=O;ind<MAX_RECT_NUMBER;ind++)1

语句"back_sum = sum;"完全可以放在for语句之后,如下。 for (ind = 0; ind < MAX_ADD_NUMBER; ind++) { sum += ind; } back_sum = sum; /* backup sum */ (5)不应花过多的时间拼命地提高调用不很频繁的函数代码效率。对代码优化可提高效率,但若考虑 不周很有可能引起严重后果。 (6)在多重循环中,应将最忙的循环放在最内层,以减少CPU切入循环层的次数。示例:如下代码效 率不高。 for (row = 0; row < 100; row++) { for (col = 0; col < 5; col++) { sum += a[row][col]; } } 可以改为如下方式,以提高效率。 for (col = 0; col < 5; col++) { for (row = 0; row < 100; row++) { sum += a[row][col]; } } (7)尽量减少循环嵌套层次。 (8)避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中。目的是减少判断次数。循 环体中的判断语句是否可以移到循环体外,要视程序的具体情况而言,一般情况,与循环变量无关 的判断语句可以移到循环体外,而有关的则不可以。 示例:如下代码效率稍低。 for (ind = 0; ind < MAX_RECT_NUMBER; ind++) { if (data_type == RECT_AREA) { area_sum += rect_area[ind]; } else { rect_length_sum += rect[ind].length; rect_width_sum += rect[ind].width; } } 因为判断语句与循环变量无关,故可如下改进,以减少判断次数。 if (data_type == RECT_AREA) { for (ind = 0; ind < MAX_RECT_NUMBER; ind++) { area_sum += rect_area[ind]; } } else { for (ind = 0; ind < MAX_RECT_NUMBER; ind++) {

rect_length_sum += rect[ind].length;rect_width_sum += rect[ind].width;71(9)尽量用乘法或其它方法代替除法,特别是浮点运算中的除法一一浮点运算除法要占用较多CPU资源。示例:如下表达式运算可能要占较多CPU资源。#definePA/3.1416radius = circle_length / (2 * PAl);应如下把浮点除法改为浮点乘法。#definePA/RECIPROCAL(1/3.1416)//编译器编译时,将生成具体浮点数radius=circle_length *PAI_RECIPROCAL/2;(10)不要一味追求紧凑的代码,因为紧凑的代码并不代表高效的机器码。8质量保证(1)代码质量保证优先原则:①正确性,指程序要实现设计要求的功能。②稳定性、安全性,指程序稳定、可靠、安全,③可测试性,指程序要具有良好的可测试性。④规范可读性,指程序书写风格、命名规则等要符合规范。③全局效率,指软件系统的整体效率。③局部效率,指某个模块/子模块/函数的本身效率。①个人表达方式/个人方便性,指个人编程习惯。(2)过程/函数中分配的内存,在过程/函数退出之前要释放,过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭。分配的内存不释放以及文件句柄不关闭,是较常见的错误,而且稍不注意就有可能发生。这类错误往往会引起很严重后果,且难以定位示例:下函数在退出之前,没有把分配的内存释放。typedefunsignedcharBYTEint example_fun(BYTEgt_len,BYTE*gt_code)BYTE *gt_buf;gt_buf =(BYTE *)malloc (MAX_GT_LENGTH);... //program code, include check gt_buf if or not NULL.I* global title length error */if (gt_len > MAX_GT_LENGTH)treturnGTLENGTHERROR;//忘了释放gtbuf7...Il other program codefree( gt_buf );1(3)防止内存操作越界。内存操作主要是指对数组、指针、内存地址等的操作。内存操作越界是软件系统主要错误之一,后果往往非常严重,所以当我们进行这些操作时一定要仔细小心

rect_length_sum += rect[ind].length; rect_width_sum += rect[ind].width; } } (9)尽量用乘法或其它方法代替除法,特别是浮点运算中的除法——浮点运算除法要占用较多CPU资 源。示例:如下表达式运算可能要占较多CPU资源。 #define PAI 3.1416 radius = circle_length / (2 * PAI); 应如下把浮点除法改为浮点乘法。 #define PAI_RECIPROCAL (1 / 3.1416 ) // 编译器编译时,将生成具体浮点数 radius = circle_length * PAI_RECIPROCAL / 2; (10)不要一味追求紧凑的代码,因为紧凑的代码并不代表高效的机器码。 8 质量保证 (1)代码质量保证优先原则: ①正确性,指程序要实现设计要求的功能。 ②稳定性、安全性,指程序稳定、可靠、安全。 ③可测试性,指程序要具有良好的可测试性。 ④规范/可读性,指程序书写风格、命名规则等要符合规范。 ⑤全局效率,指软件系统的整体效率。 ⑥局部效率,指某个模块/子模块/函数的本身效率。 ⑦个人表达方式/个人方便性,指个人编程习惯。 (2)过程/ 函数中分配的内存,在过程/ 函数退出之前要释放,过程/ 函数中申请的(为打开文件而使用 的)文件句柄,在过程/ 函数退出之前要关闭。分配的内存不释放以及文件句柄不关闭,是较常见的错 误,而且稍不注意就有可能发生。这类错误往往会引起很严重后果,且难以定位。 示例:下函数在退出之前,没有把分配的内存释放。 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 free( gt_buf ); } (3)防止内存操作越界。内存操作主要是指对数组、指针、内存地址等的操作。内存操作越界是软件 系统主要错误之一,后果往往非常严重,所以当我们进行这些操作时一定要仔细小心

(4)编程时,要防止差1错误。此类错误一般是由于把"="误写成">"等造成的,由此引起的后果,很多情况下是很严重的,所以编程时,一定要在这些地方小心。当编完程序后,应对这些操作符进行彻底检查。(5)要时刻注意易混淆的操作符。当编完程序后,应从头至尾检查一遍这些操作符,以防止拼写错误。形式相近的操作符最容易引起误用,如C/C++中的"="与"=="、""与""、"&"与"&&"等,若拼写错了,编译器不一定能够检查出来。(6)有可能的话,if语句尽量加上else分支,对没有else分支的语句要小心对待;switch语句必须有default分支。(7)不要滥用goto语句。goto语句会破坏程序的结构性,所以除非确实需要,最好不使用goto语句。(8)sizeof操作符不能用在包含边界作用(sideeffect)的表达式上,例:Int32 t= i;Int32 t= j;j= sizeof(i= 1234);表达式i=1234并没有执行,只是得到表达式类型int的size。(9)逻辑操作符&&或者右边不能包含边界作用(sideeffect)。例:if(ishight)&&(x==i++))如果ishight=0那么i++不会被执行。(10)++和-不能和其他表达式用在一个表达式中。(11)赋值语句不能用在一个产生布尔值的表达式中,例:if ((x = y) != O)...更差的用法:if (x = y)...(12)浮点表达式不应该测试其是否相等或者不相等,for控制表达式中不要包含任何浮点类型。(13)数字变量作为for循环的循环计数不要在循环体内部被修改。例:flag=1;for (i=0;(i=0)//将出现下溢1../l programcode1当size等于0时,再减1不会小于0,而是0xFF,故程序是一个死循环。应如下修改charsize;l/从unsignedchar改为chaiwhile (size-- >= 0)

(4)编程时,要防止差1 错误。此类错误一般是由于把"="误写成">"等造成的,由此 引起的后果,很多情况下是很严重的,所以编程时,一定要在这些地方小心。当编完程序后,应对 这些操作符进行彻底检查。 (5)要时刻注意易混淆的操作符。当编完程序后,应从头至尾检查一遍这些操作符,以防止拼写错 误。形式相近的操作符最容易引起误用,如C/C++中的"="与"=="、"|"与"||"、"&"与"&&"等,若拼写错 了,编译器不一定能够检查出来。 (6)有可能的话,if 语句尽量加上else 分支,对没有else 分支的语句要小心对待;switch 语句必须有 default 分支。 (7)不要滥用goto 语句。goto语句会破坏程序的结构性,所以除非确实需要,最好不使用goto语句。 (8)sizeof操作符不能用在包含边界作用(side effect)的表达式上,例: Int32_t = i; Int32_t = j; j = sizeof(i = 1234); 表达式i = 1234并没有执行,只是得到表达式类型int的size。 (9)逻辑操作符&&或者||右边不能包含边界作用(side effect)。例: if (ishight) && (x == i++)) 如果ishight=0那么i++不会被执行。 (10)++和-不能和其他表达式用在一个表达式中。 (11)赋值语句不能用在一个产生布尔值的表达式中,例: if ((x = y) != 0). 更差的用法: if (x = y). (12)浮点表达式不应该测试其是否相等或者不相等,for控制表达式中不要包含任何浮点类型。 (13)数字变量作为for循环的循环计数不要在循环体内部被修改。例: flag=1; for (i=0;(i= 0) // 将出现下溢 { . // program code } 当size等于0时,再减1不会小于0,而是0xFF,故程序是一个死循环。应如下修改。 char size; // 从unsigned char 改为char while (size- >= 0)

{..//lprogramcode1(19)使用变量时要注意其边界值的情况。示例:如C语言中字符型变量,有效值范围为-128到127。故以下表达式的计算存在一定风险。char chr = 127;intsum=200;chr+=1;//127为chr的边界值,再加1将使chr上溢到-128,而不是128。sum+=chr;l/故sum的结果不是328,而是72。若chr与sum为同一种类型,或表达式按如下方式书写,可能会好些sum=sum+chr+1;(20)系统应具有一定的容错能力,对一些错误事件(如用户误操作等)能进行自动补救。9宏(1)用宏定义表达式时,要使用完备的括号。示例:如下定义的宏都存在一定的风险。#defineRECTANGLE_AREA(a,b)a *b#defineRECTANGLEAREA(a,b)(a*b)#define RECTANGLE_AREA(a, b)(a)*(b)正确的定义应为:#defineRECTANGLE_AREA(a,b)(a)*(b)(2)将宏所定义的多条表达式放在大括号中。示例:下面的语句只有宏的第一条表达式被执行。为了说明问题,for语句的书写稍不符规范。#define INTI_RECT_VALUE(a, b)Ia=0;b = 0;for(index=O;index<RECT_TOTALNUM;index++)INTI RECT VALUE(rect.a, rect.b);正确的用法应为:#define INTI_RECT_VALUE(a, b )(Ia = 0;lb = 0;I}for (index = O; index<RECT_TOTAL_NUM; index++)1INTI_RECT_VALUE(rect[index].a, rect[index].b );}(3)使用宏时,不允许参数发生变化。示例:如下用法可能导致错误#define SQUARE(a)(a)*(a))int a= 5;int b;b=SQUARE(a++);//结果:a=7,即执行了两次增1。正确的用法是:b = SQUARE(a);a++;II结果:a=6,即只执行了一次增1

{ . // program code } (19)使用变量时要注意其边界值的情况。示例:如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; (20)系统应具有一定的容错能力,对一些错误事件(如用户误操作等)能进行自动补救。 9 宏 (1)用宏定义表达式时,要使用完备的括号。示例:如下定义的宏都存在一定的风险。 #define RECTANGLE_AREA( a, b ) a * b #define RECTANGLE_AREA( a, b ) (a * b) #define RECTANGLE_AREA( a, b ) (a) * (b) 正确的定义应为: #define RECTANGLE_AREA( a, b ) ((a) * (b)) (2)将宏所定义的多条表达式放在大括号中。示例:下面的语句只有宏的第一条表达式被执行。为了 说明问题,for语句的书写稍不符规范。 #define INTI_RECT_VALUE( a, b )\ a = 0;\ b = 0; for (index = 0; index < RECT_TOTAL_NUM; index++) INTI_RECT_VALUE( rect.a, rect.b ); 正确的用法应为: #define INTI_RECT_VALUE( a, b )\ {\ a = 0;\ b = 0;\ } for (index = 0; index < RECT_TOTAL_NUM; index++) { INTI_RECT_VALUE( rect[index].a, rect[index].b ); } (3)使用宏时,不允许参数发生变化。示例:如下用法可能导致错误。 #define SQUARE( a ) ((a) * (a)) int a = 5; int b; b = SQUARE( a++ ); // 结果:a = 7,即执行了两次增1。 正确的用法是: b = SQUARE( a ); a++; // 结果:a = 6,即只执行了一次增1

已到末页,全文结束
刷新页面下载完整文档
VIP每日下载上限内不扣除下载券和下载次数;
按次数下载不扣除下载券;
注册用户24小时内重复下载只扣除一次;
顺序:VIP每日次数-->可用次数-->下载券;
相关文档