文章目录
第七章 高质量的子程序
子程序 routine
子程序的目的: 子程序只完成一件事,提高程序的可管理性、可读性、可修改性。
高内聚性:是指子程序中各种操作之间联系的紧密程度。
函数与过程的区别:
- 函数是有return返回值的;函数的名字应该描述其返回值
- 过程没有返回值,或者返回类型为void;过程的名字应该是 动词+宾语
1.创建子程序的理由
- 降低复杂度
- 避免代码重复
- 简化复杂的逻辑操作
- 隐藏实现细节
- 创建简单好用的子程序
2.内聚性
功能内聚性:一个子程序仅执行一项操作,比如 cos
不好的内聚性:通信内聚性、时间内聚性、逻辑内聚性、过程内聚性
3.好的子程序名字
- 不要仅通过数字来描述子程序名字
- 过程起名时使用动词+宾语
如 PrintDocument() - 子程序的总长度最在150行以内
4.子程序的参数
- 按照输入-修改-输出的顺序排列参数
C++中用CONST关键字定义输入参数合适
- 如果几个子程序都使用了类似的参数,应该使这些参数的排列顺序保持一致
- 把状态或者布尔变量放到参数的最后
- 不要把子程序的参数用做工作变量
// 正确的使用方法 引入工作变量 workValue
int Sample(int input)
{
int workValue=input*input;
return workValue;
}
5.使用函数时要注意的问题
- 写函数时,写一个状态变量作为显示参数的过程
例如:
report.FormatOutput(formattedReport,outputStatus)
{ if(outputStatus=success)
then
}
2. 设置函数返回值注意事项:
- 检查所有可能的返回路径,初始化返回值
- 不要返回指向局部数据的引用或指针
3.宏子程序 - 把宏表达式整个包含在括号内
- 把包含多条语句的宏用大括号括起来
第八章 防御式编程
概念:子程序应该不因传入错误数据而被破坏,哪怕是由其他子程序产生的错误数据。
1.保护程序免遭非法输入数据的破坏
- 检查外部数据,如接口数据
- 检查所有的输入数据
- 决定如何处理错误的输入数据
2.断言 assertions
断言用于处理代码中不应该发生的错误,是用在开发和维护期间使用的,通常是一个子程序或宏。
断言包括两个参数:一个描述假设为真时的情况的布尔表达式,和另一个断言为假时需要显示的信息。
assert denominator!=0:"denominator is unexpectedly equal to 0.";
char *strcpy(char *strDest, const char *strSrc)
{
char *address = strDest;
assert((strDest != NULL) && (strSrc != NULL));
while ((*strDest++ = *strSrc++) != ’\0’)
;
return address;
}
其中包含断言assert( (strDest != NULL) && (strSrc != NULL) ),它的意思是源和目的字符串的地址都不能为空,一旦为空,程序实际上就执行错误了,会引发一个abort。
3.错误代码的处理
当系统遇到错误时,要决定系统里哪些部分应该直接处理错误,哪些部分只报告所发生的错误。
遇到错误时的处理方法:
- 返回中立值;
- 换用下一个正确的数据;
- 换用最接近的合法值;
- 返回与前次相同的数据;
- 把警告信息记录到日志文件中;
理解程序的正确性和健壮性
在架构层次上决定使用对错误的处理方法,比如让高层的代码处理错误,底层的代码只需报告错误。
在每个系统调用后检查错误码,一旦检测到错误,就记下错误代号和它的描述信息。
4.异常的处理 exception
子程序使用throw抛出一个异常对象,再被调用链上层其他子程序的try-catch语句捕获
5.各种错误的处理机制:
- 在局部处理错误
- 使用错误码传递错误
- 在日志文件中记录调试信息
- 关闭系统等
第十章 使用代码的一般事项
变量初始化原则
-
关闭隐式声明,隐式声明函数带来问题;
隐式声明 -
要声明全部的变量
- 声明变量的时候初始化;
- 在靠近变量第一次使用的位置初始化它;
- 可能的情况使用const或者final;
- 需要重新初始化的代码位于重复执行的代码内部; 双重for循环,重新初始化计数变量
- 在程序开始时初始化工作内存;
作用域 : 使变量引用局部化
变量声明和定义时要同时减小变量跨度和生存时间
先选择小的作用域
第十一章 变量名的力量
1.注意事项
- 对变量的描述就是最好的变量名,例如:seatCount 小写字母+大写首字母
- 变量声明要容易理解,最好时整个英语单词的描述,而不是简称,比如 当前日期 currentDate,而不是date。
- 避免使用常用的名字作为变量名,如date,time等
- 好的名字表达是“什么”what,而不是“如何”how,比如:calcVal比sum的计算痕迹明显
- 变量名控制在9-16个字符内,确保含义清晰
正好:numTeamMembers,seatCount
太短:m,n,max
- 表示计算值的限定词,比如Total,Sum,Average,这类限定词加到名字的最后。
- 变量名中最重要的那部分一般放在最前面,比如:revenueToal,expenseTotal;
- 表示总数时用Count,customerCount;表示索引时用Index,customerIndex;来代替Num
2.变量的命名
循环变量的命名:
- 简单的循环变量:i,j,k
- 变量在循环外使用:recordCount
- 嵌套循环时:teamIndex,eventIndex
状态变量的命名:
不要使用Flag,使用枚举类型和具名常量,
const int PRINTABLE_CHAR=0x04
if(characterType & PRINTABLE_CHAR)
临时变量
- 临时变量也要有自己的名字,不要使用temp
布尔变量
- 有用的布尔变量名:表示0 1 状态的名字:done,error,found,ok,success
- 给布尔变量赋予隐含的“真假”含义名字,sourceFileFound
3.非正式命名规则
命名规则能够区分局部数据、类数据、全局数据,还应该可以区分类型名、具名常量、枚举类型名和变量名。
- 区分变量名和子程序名字:变量名以字母小写开始,子程序名以字母大写开始;
variableName; RoutineName() - 区分类和对象;
Widget employeeWidget;
LongerWidget fullEmployeeWidget; - 全局变量,加上g_前缀,g_RunningTotal
- 成员变量,加上m_前缀
- 标识具名常量,包括typedef,全部大写,用下划线分割
- 标识类型声明,加上t_前缀,t_Color
- 标识枚举类型的元素,加上e_前缀,同时该类型的成员名加上基于该类型的前缀,如Color_
- 在不能保证输入参数是只读变量的语言里标识只读参数,如在C++里,使用 & const*,const前缀不能出现在赋值符号左边
- 格式化命名 大小写命名或者分隔符,我使用大小写命名,第一个字母为小写
命名规则实例:
4.标准前缀
-
UDT 用户自定义类型缩写
-
标准前缀,比如:p g i min max lim first last
-
避免在名字中使用数字,比如 file1,file2
-
避免在名字中包含容易混淆的字符,比如数字1和小写字母l,1和I,0和O,2和z,5和S,