1什么是防御性编程?防御性编程,顾名思义,是一种小心谨慎的编程方法。为了开发可靠的软件,我们设计系统中的每个组件,使其尽可能地“保护”自己。我们努力通过明确检查代码中的假设来防止我们的代码以会表现出不正确行为的方式被调用。防御性编程使我们能够及早发现较小的问题,而不是等待它们发展成大灾难。它开发软件的过程是:防御性编程的一些反对者和支持者总结如下:反对者:它降低了代码的效率;即使是少量的附加代码也需要一些额外的执行时间。对一个功能来说可能无所谓,但对一个由10万个功能组成的系统来说,问题就严重了。每一种防御方法都需要一些额外的工作;支持者:防御性编程可以节省很多调试时间,让你做更有意义的事情。编写可以运行但速度稍慢的代码要比大部分时间运行但有时会崩溃的代码要好得多。防御性编程避免了大量的安全问题。防御性编程技巧使用良好的编码风格和合理的设计使用良好的编码风格来防止大多数编码错误。如:const关键字:关键字const可以向阅读你代码的人传达非常有用的信息。例如,在函数的形参前加上const关键字,表示这个形参在函数体中不会被修改,是一个入参。同时,合理使用关键字const,可以让编译器自然而然地保护那些不想修改的参数,防止它们被无意的代码修改,减少bug的发生。volatile关键字:在一些并行设备的硬件寄存器(如状态寄存器)、中断服务子程序中访问的全局变量、多线程应用中多个任务共享的变量前使用volatile关键字来防止编译优化。static关键字:函数体中静态变量的作用域为函数体。与auto变量不同的是,变量的内存只分配一次,所以下次调用时它的值会保持上次的值。模块中的静态全局变量可以被模块内的所有函数访问,但不能被模块外的其他函数访问。模块中的静态函数只能被本模块中的其他函数调用,该函数的使用范围仅限于声明它的模块。在位运算中,<<、>>、&、|等运算符尽量多用,/、%、*运算符尽量少用。变量和函数的名字要有意义,一个函数尽可能只做一件事。多用面向对象的思想来写代码。在进行编码之前考虑总体设计也很重要。不要着急写代码。每打一个字,都要想清楚自己要输入什么。写每一行时要三思。可能会出现什么样的错误?您是否考虑过所有可能出现的逻辑分支?缓慢、有条不紊的编程可能看起来很平凡,但它是减少错误的好方法。比如在C语言编程中,追求速度的程序员常有的一个问题就是将“==”输入为“=”,有的编译器不会警告,就会出现问题。在这里不要相信任何人意味着以怀疑的眼光看待所有的输入和所有的结果,直到你能证明代码是正确的。编码的目标要明确,不要简洁,简单是一种美,不要让你的代码太复杂。也就是说,写出来的代码要合乎逻辑,可读性强。在打开所有警告的情况下编译代码中的任何警告都应立即更正。请注意,警告的出现总是有原因的。即使您认为警告无关紧要,也不要忽略它。使用安全的数据结构我们最常见的一些安全风险可能是由缓冲区溢出引起的。缓冲区溢出是由不正确使用固定大小的数据结构引起的。例如下面的代码:char*unsafe_copy(constchar*source){char*buffer=newchar[10];strcpy(buffer,source);returnbuffer;}如果source中的数据长度超过10个字符,会导致其他问题。我们可以改成下面的形式:char*safe_copy(constchar*source){char*buffer=newchar[10];strncpy(buffer,source,10);//把strcpy换成strncpy来保护这段代码段returnbuffer;}检查所有一个函数的返回值如果一个函数有返回值,他这样做肯定是有原因的。检查返回值,如果返回值是错误代码,则必须识别此代码并处理所有错误。不要让bug悄悄潜入你的程序;大多数细微错误的出现是因为程序员不检查返回值。明智地处理内存执行期间获取的任何资源都必须完全释放。在声明变量的地方初始化所有变量如果你不小心使用了一个没有初始化的变量,你的程序每次运行都会得到不同的结果,这取决于当时内存中有什么垃圾。这会造成很多随机行为,给搜索带来很多麻烦。因此,每个变量在声明时都需要初始化。同时,编码时要注意一些细则。提供默认行为:defaultcase的执行在Switch语句中清晰显示。同样,如果你要写一些没有else子句的if语句,停下来想想你是否应该处理检查值的上限和下限的逻辑默认值:以确保值变量在每次评估时都不会溢出,即数据类型的使用要谨慎,注意变量声明的强制转换是否合理,使变量的声明位置尽量靠近使用的位置,所以以防止它干扰代码的其他部分。添加合理的异常处理和正确的日志文件常量。优秀的程序应该:关注代码的健壮性确保每个假设都明确反映在防御代码中希望代码在输入无用信息时表现正确编程时仔细考虑你写的内容编写保护你免受他人伤害的代码愚蠢伤害了代码。
