防御性编程

防御性编程是一种编程哲学,强调程序应能够抵御错误输入的影响,即使这些错误源自其他部分的代码。通过采取预防措施,确保子程序在面对异常数据时仍能保持稳定,程序员可以提高软件的健壮性和可靠性。这种理念源于防御性驾驶,旨在承认并准备应对潜在的问题和未来修改需求。
摘要由CSDN通过智能技术生成

第八章 防御性编程

   防御性编程并不是说让你在编程时持“防备批评或攻击”的态度——“它就是这么工作!”这一概念来自防御式驾驶。防御性编程的主要思想是:子程序应该不因传入错误数据而被破坏,哪怕是由其它子程序产生的错误数据。更一般地说,其核心想法是要承认程序都会有问题,都需要被修改,聪明的程序员应该根据这一点来编程序。

8.1 保护程序免遭非法数据的破坏
    检查所有来源与外部的数据的值
    当从文件、用户、网络或其他外部接口中获取数据是,应检查所获得的数据值,以确保它在允许的范围内。对于数值,要确保它在可接受的取值范围内;对于字符串,要确保其不超长。如果字符串代表的是某个特定范围内的数据,那么要确认其取值合乎用途,否则就应该拒绝接受。如果你在开发需要确保安全的应用程序,还要格外注意哪些狡猾的可能是攻击你的系统的数据,包括其图灵缓冲区溢出的数据、注入的SQL命令、注入的HTML或XML代码、整数溢出以及传递给系统调用的数据,等等。
    检查子程序所有输入参数的值
    检查子程序输入参数的值,事实上和检查来源于外部的数值一样,只不过数据是来自于其他子程序而非外部接口。
    决定如何处理错误的输入数据
    一旦检测到非法的参数,你应该如何处理它呢?根据情况的不同,你可以从十几种不同的方案中选择其一。防御性编程的最佳方式就是在一开始不要代码中引入错误。使用迭代式设计、编码前先写伪代码、写代码前先写测试用例、低层设计检查等活动,都有助于防止引入错误。
8.2 断言
    断言(assertion)是指在开发期间使用的、让程序在运行时进行自检的代码(通常是一个子程序或宏)。断言为真,则表明程序运行正常,而断言为假,则意味着它已经在代码中发现了意料之外的错误。
    断言对于大型的复杂程序或可靠性要求极高的程序来说尤其有用。通过使用断言,程序员能够更快地排查初音修改代码或者别的原因,而弄进程序里的不匹配的接口假定和错误等。
    一个断言通常含有两个参数:一个描述假设为真时的情况的布尔表达式,和一个断言为假时需要显示的信息。在C++中分为动态断言和静态断言两种。
    动态断言:assert(常量表达式)它是在程序运行期间进行断言,对程序的性能有一定的影响,所以通常情况下动态断言只在程序的调试版本中有效。
    静态断言:static_assert(常量表达式, 错误消息提示字符串) 它在程序编译期间断言,不生成任何目标代码,所以不影响程序的性能。
    断言可以用于在代码中说明各种假定,澄清各种不希望的情形。可以用断言检查如下这类假定:
    ·输入参数或输出参数的取值处于预期的范围内;
    ·子程序开始(或结束)执行时文件或流是处于打开(或关闭)的状态;
    ·子程序开始(或结束)执行时,文件或流的读写位置处于开头(或结尾)处;
    ·文件或流已用只读、只写或可读可写方式打开;
    ·仅用于输入的变量的值没有被子程序所修改;
    ·指针非空;
    ·传入子程序的数组或其他容器至少能容纳X个数据元素;
    ·表已初始化,存储着真实的数值;
    ·子程序开始(或结束)执行时,某个容器是空的(或慢的);
    ·一个经过高度优化的复杂子程序的运算结果和相对缓慢但代码清晰的子程序的运算结果相一致。

    当然以上也只是列出了一些假定,你还可以在程序中包括更多可以用断言来说明的假定。
    建立自己的断言机制
    C++中标准的assert宏并不支持文本信息。因此我们可以自己改进,下面就是一个改进的ASSERT宏实现:
C++示例:一个实现断言的宏
#define ASSERT(condition, message) (	                \
	if( !(condition) ) {				\
		LogError( "Assertion failed: ",	        \
			#condition, message );		\
		exit(EXIT_FAILURE);			\
	}						\
)
    使用断言的指导建议
用错误处理代码来处理预期会发生的状况,用断言来处理绝不应该发生的状况。断言是用来检查永远不应该发生的情况,而错误处理代码是用来检查不太可能经常发生的非正常情况,这些情况是能在写代码时就预料到的,而在产品中也要处理这些情况。错误处理通常用来检查有害的输入数据,而断言是用于检查代码中的bug。
    用错误处理代码来处理反常情况,程序就能够很从容地对错误做出反应。如果在发生异常情况的时候出发了断言,那么要采取的更正的措施就不仅仅是对错误做出恰当地反映了——而是应该修改程序源代码并重新编译,然后发布软件的新版本。
    有种方式可以让你更好地理解断言,那就是把断言看作是可执行的注解——你不能依赖它来让代码正常工作,但与编程语言中的注释相比,它能更主动地对程序中的假定作出说明。
    避免把需要执行的代码放到断言中。如果把代码写在断言里,那么当你关闭断言功能时,编译器很可能就把这写代码排除在外了。比如说,你写了这么一个断言:
ASSERT(performAction(), "Couldn't perform action");
    这段代码的问题在于,如果未编译断言语句,那么其中用于执行操作的代码也就不会被编译。应该把需要执行的语句提取出来,并把其运算结果赋给状态变量,在对这些状态变量进行判断。下面这样使用断言就很安全:
actionPerformed = PerformAction();
ASSERT(actionPerformed, "Couldn't perform action");
    用断言来注释并验证前条件和后条件。前条件(preconditions)和后条件(postconditions)是一种名为“契约式设计(design by contract)”的程序设计和开发方法的一部分。使用前
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值