第十章, 使用变量的一般事项
前言
把蓝图设计得精细到已经完全展现出所有的细节实在是一种低效的做法
10.1 数据认知
10.2 轻松掌握变量定义
隐式声明:
是指你在使用一个未定义的变量的时候,编译器会自动为你声明此变量。隐式变量声明对任何一种语言来说都是最具危险的特性之一。
避免的方法:
1、 关闭隐式什么。
2、 什么全部的变量。
3、 遵循某种命名规则。
4、 检查变量名。
10.3 变量初始化原则
1、 在声明变量的时候初始化。
2、 遵循就近原则(Principle of Proximity),在靠近变量第一次使用的为止初始化它(我习惯要改一下了。)。
3、 在理想情况下,在靠近第一次使用变量的位置声明和定义该变量。()
4、 在可能的情况下,使用final和const。final是java中类似于const的关键字。
5、 特别注意计时器和累加器。
6、 在类的构造函数理初始化类的数据成员。
7、 检查是否需要重新初始化。特别是循环中的变量。
8、 一次性初始化具名常量:用可执行代码来初始化变量。
9、 检查输入参数合法性。
10、 使用内存访问检查工具。
11、 在程序开始时初始化工作内存。
10.4 作用域
作用域或者可见性是指变量在程序内的可见和可引用的范围。
使变量应用局部化:
介于同一个变量多个引用点之间的代码可成为攻击窗口,在这个窗口中新增代码,可能会不当的修改此变量。
一般而言,把对一个变量的引用局部化,即把引用点尽可能集中在一起总是一种很好的做法。主要的好处是提高程序的可读性和可维护性。
可以用跨度来衡量:引用间相隔的代码行数。
尽可能的缩短变量的存活时间:
一个变量存在期间所跨越的语句总数。跨度表明变量引用的集中程度,存活时间表明变量经历的语句。
低存活时间的好处是减小攻击窗口,使你对代码有更准确的认识(提高可读性),减少初始化错误。
最后,一个明显的好处是便于程序重构,如果一个程序拆分为多个小的程序,短的存活时间更有价值。
用跨度和生存时间来考察全局变量,会发现全局变量跨度和生存时间都很长——这是避免使用全局变量的好的理由之一。
减小作用域的一般原则:
1、 在循环开始之前再去初始化改循环里使用的循环变量,而不是在该循环所属的子程序的开始处初始化这些变量。
2、 直到变量即将被使用时再为其赋值。把声明和定义放在使用之前。
3、 把相关语句放在一起。减少变量的跨度和生存时间。
4、 把相关的语句组提取成功单独的子程序。把一个长的子程序拆分为更小的、单独的子程序可以缩小变量的作用域。
5、 开始时才偶那个最严格的可见性,然后根据需要扩展变量的作用域。当对变量作用域犹豫不决时,应该倾向于选择该变量所能具有的最小的作用域:首先将变量限制于某个特定的循环,然后是局限于某个子程序,其次是类的private变量,protected变量,再其次对包()可见,最后不得已的情况下再把它作为全局变量。
关于对变量作用域的态度,取决于程序员如何看待“方便性”和“智力上的可管理性”。作用域越大,在写代码时越方便。但是写出的程序更难于理解、阅读、调试和维护。
10.5 持续性
持续性是对数据项的生命周期的另一种描述。
1、 特定代码段或子程序生命周期。
2、 动态申请。
3、 程序生命周期。
4、 永久生存。
为了防止变量已经消失,可以:
1、 程序中加入调试或断言来判断。
2、 在抛弃它的时候,给他附上不合理的值。
3、 编写代码的时候假设变量没有持续性。
4、 养成在使用所有时间之前都声明和初始化的习惯。
10.6 绑定时间
绑定时间:把变量和它的值绑定在一起的时间。
一般而言,绑定的时间越晚,灵活性越高,复杂度越大。
硬编码。
编译时,
加载时。
运行时。
即时。
10.7 数据类型和控制结构之间的关系
1、 序列型数据翻译为程序中的顺序语句。
2、 选择型数据翻译为程序中的if和else语句。
3、 迭代型数据翻译为程序中的for,while,等循环结构。
10.8 为变量指定单一用途
1、 每个变量只用于单一用途。参加的是在不同的场合使用同一个临时变量。
2、 避免让代码具有隐含意义。当其代表不同事物时,具有不同的取值集合。我用过一些,用一个值的大小范围表示不同的含义。这种滥用在技术领域里称为混合耦合。
3、 确保使用了所有的变量。
CHECKLIST: General Considerations In Using Data核对表:使用数据的一般注意事项初始化变量 1、 每一个子程序都检查其输入参数的有效性吗? 2、 变量声明位置靠近变量第一次使用的位置吗? 3、 尽可能在声明变量的时候初始化变量吗? 4、 如果无法同时声明和初始化变量,有没有在靠近第一次使用变量的位置声明变量? 5、 计数器和累加器经过了适当的初始化了吗?如果需要再一次使用,之前重新初始化了吗? 6、 适当的重新初始化“需要重复执行的代码里的变量”了吗? 7、 代码在经过编译器编译时是不是没有告警?(你启用了所有的告警选项了吗?) 8、 如果你所使用的语言允许隐式声明,你为此可能引起的问题做好补偿措施了吗? 使用数据的其他事项 1、 如果可能,所有的变量都被定义为具有最小的作用域吗? 2、 各变量的引用点都尽可能的集中在一起吗?对同一个变量的两次相邻引用,或者整个变量的生命周期都这样做了吗? 3、 控制结构符合数据类型吗? 4、 所有声明的变量都用到了吗? 5、 变量都在合适的时间绑定了吗?——也就是所,你有意识的在晚期绑定所带来的灵活性和增加的复杂度之间做出平衡了吗? 6、 每个变量有且仅有一项用途吗? 7、 每个变量的含义都很明确且没有隐含意义吗? |
本章要点
1、 数据初始化很容易出错,使用本章所描述的初始化原则。
2、 最小化每个变量的作用域。把同一个变量的引用点集中在一起。把变量限定在子程序或类的范围内。避免使用全局变量。
3、 把使用相同变量的语句尽可能的集中在一起。
4、 早期绑定数据会降低灵活性,但有助于减小复杂度。晚期绑定可以增加灵活性,但同时又增加复杂度。
5、 把每个变量用于唯一个用途。
第十一章, 变量名的力量
前言
11.1 选择好的变量名的注意事项
最重要的命名注意事项
1、 该名字要完全,准确的描述出变量所代码的事物。
2、 命名的词语尽量选取普通,易懂的词语。
以问题为导向:
命名要反映的是解决“什么”(what),而不是“如何”(how)。即,命名要反映的是现实世界的事物,而不是计算机解决方案的事物。
最适合的名字的长度
太短则信息不重复,太长则难于书写,且结构模糊。
研究表明,变量名的平均长度位于10到16之间时,程序员花费的时间是最小的。当然只是平均长度。如果长度过于短,则要检查一下,确保名字的含义足够清晰。
作用域对变量名的影响
研究表明,较长的名字适用于很少用的变量或者全局变量,较短的名字适用于局部变量或循环变量。作为一项防御式编程策略,细心的程序员要避免使用短的变量名。
使用命名空间,对全局变量加以限定。以后要关注一下c++的命名空间。
变量中的计算值限定词:
把计算值:总额,平均值,最大值,最小值等放在变量的后面。把变量中最重要大部分,即表示变量含义的部分放在最前面:revenueTotal,revenueMax。慎用num,尽量用更明确的词来代替:total,index。
11.2 为特定类型的数据命名
为循环下标命名
1、 如果一个变量要在循环之外使用,则使用一个更有意义的变量名。
2、 循环很长,则要使用更有意义的变量名。
3、 尽量使用有意义的循环变量来代替:i、j、k。
为状态变量命名
为状态变量起一个比flag更好的名字 用枚举类型,具名常量,或用作具名常量的全局变量对其赋值。
为临时变量命名:
临时变量通常是一个信号,说明程序员还没有完全把问题搞清楚。
1、 警惕临时变量。
2、 将临时变量命名更为明确,以使通过变量可以获得更多的信息。
为布尔变量命名
典型的布尔变量名:
1、 done,表示某件事情已经完成。
2、 error,表示错误已经发生。
3、 found,表示某个值已经找到,找到前为false,找到后为true。
4、 success,表示成功。
给布尔变量赋予隐含“真/假”含义的名字
使用肯定的布尔变量:尽量少使用notfound,notdone。
为枚举类型命名:
Color_Red:前面表示枚举的类,后面表示具体的值。
为常量命名:应该描述常量的表示的含义。
11.3 命名规则的力量
11.4 非正式命名规则
1、 区分变量名和子程序名 变量名以小写字母开始,子程序名称以大写字母开始。
2、 标识全局变量
3、 标识成员变量
4、 标识类型声明:t_
5、 标识具名常量。c_或者全大写,大写加下划线。
6、 标识枚举类型常量。
名字对于代码读者的意义要比作者更重要。要让读者读代码的时候,很容易,很舒服,自然。
11.7 应该避免的名字
避免使用令人误解的名字和缩写。
避免使用具有相似含义的名字。
避免使用具有不同含义,但是具有相似名字的变量。
避免使用发音相近的名字。
避免在名字中使用数字。
避免在名字中拼错单词。
不要仅靠大小写来区分变量。
避免使用多种自然语言。
避免使用标准类型,变量,子程序的名字。
不要使用与变量含义完全无关的名字。
避免在名字中使用易混的名字。
本章对我更有意义的是前两节。
把这一章的核对表还是打印一下吧,还是很有意义的。
第十二章, 基本数据类型
前言
12.1 数值概论
1、 避免使用神秘数值,使用具名常量代替。
2、 可以使用0、1
3、 预防除0错误。
4、 使类型转换明显。
5、 避免使用混合类型的比较。
12.2 整数
1、 检查整数除法。
2、 检查整数溢出。
3、 检查之间结果溢出。
12.3 浮点数
1、 避免数量级相差巨大的数之间比较。
2、 避免等量判断。
3、 处理舍入差错。
12.3 字符和字符串
1、避免使用神秘字符和神秘字符串。我使用的“global:”应该是一个神秘字符,把它给替换掉。另外,还有一些表示特殊含义的字符串,比如,正常,异常等。都用具名常量替换一下。
Bool类型变量的命名,要精确的表示出什么情况下为真,什么情况下为假,要使用肯定的描述。
12.6 枚举类型
使用枚举可以提高程序的可靠性。
定义出枚举的第一项和最后一项,用于检测循环边界。
把枚举的第一个值留作非法值。
第十三章, 不常见的数据类型
前言
13.1 结构体
13.2 使用指针的一般技巧
1、 把指针操作限制在子程序或类里面。
2、 同时声明和定义指针。
3、 用狗牌字段来检查损毁的指针。
C++中,把指针用于按值传递,把const用于按值传递。
灵活使用智能指针。
使用auto_ptr:
13.3 全局变量
全局变量对于程序的破坏性很大,不到万不得已,不要使用全局变量。
对全局变量的访问,使用访问器子程序。
用访问器子程序来取代全局变量:
访问器子程序可以实现隐藏。
对数据集中控制。
确保对变量的所有的引用得到保护。
实现信息隐藏。
可以很容易的转变为抽象数据类型。可以写出精致的代码。
便于调试。
1、 要求所有的代码通过访问器子程序来访问全局变量。这样所有全局变量定义为static,并且所有程序不可以保护“g_”开头的变量。
2、 把不同的全局变量放在不同的文件或类中。
3、 用锁定来控制对全局变量的访问。
4、 在你的访问器子程序中构建一个抽象层。要在问题域这一层次上构建访问器子程序,而不是细节实现层次上。要让访问器子程序表达抽象的意义。
5、 对一项数据的所有访问都发生在同一个抽象层次上。