分享
 
 
 

防御式编程

王朝百科·作者佚名  2010-04-14
窄屏简体版  字體: |||超大  

防御式编程是提高软件质量技术的有益辅助手段。防御式编程的主要思想是:子程序应该不因传入错误数据而被破坏,哪怕是由其他子程序产生的错误数据。这种思想是将可能出现的错误造成的影响控制在有限的范围内。

1. 在非法输入(Invalid Inputs)中保护你的程序

一个好程序,在非法输入的情况下,要么什么都不输出,要么输出错误信息。有几种方法来防止非法的输入:

(1)检查来自于外部资源(external sources)的所有数据的值,例如来源于网络的数据的值,来源于文件的数据的值。检查的目的是保证数据值在一个允许的范围内。

(2)检查每一个例程(routine)的输入参数值。

一旦非法输入被发现,那么应该根据情况进行处理。防御式编程的最佳的形式是在一开始就不引入错误。

2. 断言(Assertions)

一个断言通常是一个例程(routines)或者一个宏(marcos)。每个断言通常含有两个参数:一个布尔表示式(a boolean expression)和一个消息(a message)。一个布尔表达式的反面表示了一个错误。C 标准库提供了一个 assert 宏,它只带有一个参数,用法如下:

assert(1 == 0); // 注意 boolean expression 不要加引号

使用 assert 宏,需要包含头文件 cassert 或者assert.h,执行上面语句的结果是程序终止运行,输出与下面消息类似的消息:

Assertion failed: 1 == 0, file d:我的文档visual studio projectslearningassertassert.cpp, line 9

通常来说,我们会定义自己的 assert 宏,其目的有两个:

(1)新增参数,例如新增一个消息参数,使得 assert 宏输出更为丰富的信息。

(2)改变 assert 的行为内容。C 标准库中的 assert 宏将中断程序,实际上,我们可以让程序继续运行而不中断或者进入调试状态等,另外还可以控制消息输出的目标,即控制消息是输出到控制台还是文本文件,甚至是通过网络发出。

下面是一个 C++ 实现的断言:

#ifdef _DEBUG

#define Assert(exp, message)

{

if (!(exp))

{

std::cout << "Assertion failed: " << #exp << "

"

<< "Message: " << message << "

"

<< "line: " << __LINE__ << "

"

<< "file: " << __FILE__ << "

";

exit(EXIT_FAILURE);

}

}

#else

#define Assert(exp, message)

#endif

执行 Assert(1 == 0, "Error"); 结果为:

Assertion failed: 1 == 0

Message: Error

line: 24

file: d:我的文档visual studio projectslearningassertassert.cpp

使用断言应该注意一下的几个问题:

1)对非预期错误使用断言

断言中的布尔表达式的反面一定要描述一个非预期错误,下面所述的在一定情况下为非预期错误的一些例子:

(1)空指针。

(2)输入或者输出参数的值不在预期范围内。

(3)数组的越界。

非预期错误对应的就是预期错误,我们通常使用错误处理代码来处理预期错误,而使用断言处理非预期错误。在代码执行过程中,有些错误永远不应该发生,这样的错误是非预期错误。断言可以被看成是一种可执行的注释,你不能依赖它来让代码正常工作(《Code Complete 2》)。例如:

int nRes = f(); // nRes 由 f 函数控制, f 函数保证返回值一定在 -100 ~ 100

Assert(-100 <= nRes && nRes <= 100); // 断言,一个可执行的注释

由于 f 函数保证了返回值处于 -100 ~ 100,那么如果出现了 nRes 不在这个范围的值时,就表明一个非预期错误的出现。后面会讲到“隔栏”,那时会对断言有更加深刻的理解。

2)不要把需要执行的代码放入断言中

断言用于软件的开发和维护,而通常不在发行版本中包含断言。

需要执行的代码放入断言中是不正确的,因为在发行版本中,这些代码通常不会被执行,例如:

Assert(f()); // f 函数通常在发行版本中不会被执行

而使用如下方法则比较安全:

res = f();

Assert(res); // 安全

3)对来源于内部系统的可靠的数据使用断言,而不要对外部不可靠的数据使用断言,对于外部不可靠数据,应该使用错误处理代码。再次强调,把断言看成可执行的注释。

前条件(preconditions)和后条件(postconditions)

前条件是调用方代码在调用例程(routines)或者实例化对象之前要确保为真的条件,后条件是例程执行后或者类实例化后应满足的条件。下面是一个例子:

// 前条件,这里 nNum1 和 nNum2 的取值被前面代码所约束并保证取值在 -50 ~ 50

Assert(-50 <= nNum1 && nNum1 <= 50, "Add_nNum1");

Assert(-50 <= nNum2 && nNum2 <= 50, "Add_nNum2");

int nRes = add(nNum1, nNum2);

// 后条件

Assert(-100 <= nRes && nRes <= 100, "Add_nRes");

注意,由于 nNum1 和 nNum2 取值范围已经被约束,因此可以使用断言,但是如果 nNum1 和 nNum2 的值来源于不可靠的外部系统,那么应该使用错误处理代码,而不是使用断言。

3. 错误处理技术

这里主要讲述如何处理预期错误。

(1)终止程序运行

有些错误非常严重,如果出现,那么最好就的做法就是让程序终止并且让用户重启程序。例如,对于显示 X 光片的绘图程序,如果数据出错,那么就关闭程序,这个时候关闭程序要远远好于显示错误的数据。

(2)继续程序运行

有时候,错误出现了,但是没有必要去关闭程序,那么就有两种处理方案:

a. 在例程中处理错误

例如让例程返回一个中立值,这是一种可行的方法,中立值在有些语言里面被描述为“类型的默认值”,例如整形的中立值为 0,指针的中立值为 NULL(或 null 等)

b. 在例程外处理错误

返回一个错误码也是可行的,返回错误码意味着,错误将交由其他程序部分来处理,而不是本例程处理。

对于出现了错误,而没有终止程序的运行,这时候,你可以在日子文件中添加一个警告信息。

抉择:正确性和健壮性

有些程序要求非常高的正确性,而有些程序要求较高的健壮性,通常两者我们只能取其一。

(1)正确性意味着结果永远是正确的,如果出错,宁愿不给出结果也不要给定一个不准确的值。

(2)健壮性意味着通过一些措施,保证软件能够正常运行下去,即使有时候会有一些不准确的值出现。

4. 隔栏(barricades)

隔栏本身就是一组错误处理代码,对于内部类只需要使用断言而无需使用错误处理代码。当断言为假时,表明了问题出在了程序中而不是数据中,需要通过修改代码来消除问题。在此,请读者联系本文开始 --- “在非法输入(Invalid Inputs)中保护你的程序”这一部分进行思考。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有