1 什么是防御性编程?
顾名思义,防御性编程是一种粗疏、审慎的编程办法。为了开发牢靠的软件,咱们要设计零碎中的每个组件,以使其尽可能的”爱护”本人。咱们通过明确地在代码中对构想进行查看,这是一种致力,避免咱们的代码以将会展示错误行为的形式被调用。
防御性编程使咱们能够尽早的发现较小的问题,而不是等到它们倒退成大的劫难的时候才发现。其开发软件的过程是:
上面总结了一些防御性编程的拥护和支持者的意见:
反对者:
- 它升高了代码的效;即便是一个很小的额定代码也须要一些额定的执行工夫。它对于一个函数来说兴许不要紧,然而对于一个由 10 万个函数组成的零碎,问题就变得重大了。
- 每种防御性的做法都须要一些额定的工作;
支持者:
- 防御性编程能够节俭大量的调试工夫,使你能够去做更有意义的事件。
- 编写能够失常运行、只是速度有些慢的代码,要远远好过大多数工夫都失常运行、然而有时候会解体的代码。
- 防御性编程防止了大量的安全性问题。
防御性编程技巧
- 应用好的编码格调和正当的设计
采纳良好的编码格调,来防备大多数编码谬误。如:
- const 关键字:
关键字 const 能够给读你代码的人传播十分有用的信息。例如,在函数的形参前增加 const 关键字意味着这个参数在函数体内不会被批改,属于输出参数。
同时,正当地应用关键字 const 能够使编译器很天然的爱护那些不心愿被批改的参数,避免其被无心的代码批改,缩小 bug 的呈现。
- volatile 关键字:
在一些并行设施的硬件寄存器(如状态寄存器),中断服务子程序中会拜访到的全局变量以及多线程利用中被几个工作共享的变量前应用 volatile 关键字来避免编译优化。
- static 关键字:
- 函数体内 static 变量的作用范畴为该函数体,不同于 auto 变量,该变量的内存只被调配一次,因而其值在下次调用时仍维持上次的值。
- 在模块内的 static 全局变量能够被模块内的所有函数拜访,但不能被模块外其它函数拜访。
- 在模块内的 static 函数只可能被这一模块内的其它函数调用,这个函数的应用范畴被限度在申明它的模块内。
- 位操作运算中,尽可能应用 <<、>>、&、| 等运算符,尽可能少应用 /、%、* 运算符。
- 变量和函数的命名要有意义,并且尽可能做到一个函数只做一件事件。
- 多采纳面向对象的思维来编写代码。
- 在投入到编码工作之前,先思考大体的设计方案,这也十分要害。
- 不要仓促的编写代码
欲速则不达,每敲一个字,都要想分明你要输出的是什么。在写每一行时都三思而后行。可能会呈现什么样的谬误?你是否曾经思考了所有可能呈现的逻辑分支?加快速度,井井有条的编程尽管看上去很平庸,但这确实是缩小缺点的好方法。
如 C 语言编程中,谋求速度的程序员常常会呈现的一个问题就是将”==”谬误的输出为”=”,而有些编译器并不会正告,这就会造成问题。
- 不要置信任何人
这里是指用狐疑的眼光来扫视所有的输出和所有的后果,直到你能证实这段代码是正确的时候为止。
- 编码的指标要清晰,而不是简洁
简略是一种美,不要让你的代码过于简单。即编写的代码肯定要逻辑清晰,可读性强。
- 编译时关上所有正告开关
在你的代码中产生任何正告信息,都应立即修改代码。要晓得正告的呈现总是有起因的。即便你认为某个正告无关紧要,也不要束之高阁。
- 应用平安的数据结构
咱们最常见的一些安全隐患大略是由缓冲溢出引起的。缓冲溢出是因为不正确的应用固定大小的数据结构而造成的。例如,如下这个代码:
char * unsafe_copy(const char * source)
{char *buffer = new char[10];
strcpy(buffer,source);
return buffer;
}
如果 source 中的数据长度超过 10 个字符,它就会造成其它问题。咱们能够改成如下模式:
char * safe_copy(const char * source)
{char *buffer = new char[10];
strncpy(buffer,source,10); // 用 strncpy 代替 strcpy 能够爱护这个代码段
return buffer;
}
- 查看所有的返回值
如果一个函数返回一个值,他这样做必定是有理由的。查看这个返回值,如果返回值是一个错误代码,你就必须分别这个代码并解决所有的谬误。不要让谬误悄无声息的侵入你的程序;大多数难以觉察的谬误都是因为程序员没有查看返回值而呈现的。
- 审慎的解决内存
对于在执行期间所获取的任何资源,必须彻底开释。
- 在申明地位初始化所有变量
如果你意外的应用了一个没有初始化的变量,那么你的程序在每次运行的时候都将失去不同的后果,这取决于过后内存中的垃圾信息是什么。这样会造成很多随机的行为,给查找带来很多的麻烦。因而,须要在申明每个变量的时候就对它进行初始化。
- 同时,平时编码时还要留神一些细则
- 提供默认的行为:Switch 语句中将 default case 的执行明示进去。同样地,如果你要编写一些不带 else 子句的 if 语句,停下来想一想,你是否该解决这个逻辑上的默认状况
- 查看数值的上上限:确保每次运算数值变量都不会溢出,即数据类型的应用要审慎
- 留神强制转换是否正当
- 申明变量,能够使变量的申明地位与应用它的地位尽量靠近,从而避免它烦扰代码的其余局部
- 加正当的异样解决、日志文件
- 正确设置常量
优良的程序应该做到:
- 关怀代码是否强壮
- 确保每个构想都显示地体现在防御性代码中
- 心愿代码对无用信息的输出有正确的行为
- 在编程的时候认真思考本人所编写的代码
- 编写能够爱护本人不受其他人的愚昧挫伤的代码。