C++程序设计 ch13 程序设计的防错
发布时间:2024-08-31
发布时间:2024-08-31
C++程序设计
面向对象程序设计与实践 第13章 章 程序设计的防错
主讲人: 主讲人:杨峰
C++程序设计
本课主要内容 保证程序的正确性 异常 函数的防错 测试 调试Page 1
C++程序设计
1保证程序的正确性 保证程序的正确性
1.1什么是程序的正确性?实现正确的软件 正确的实现软件
Page 2
C++程序设计
1.2实现正确的软件 实现正确的软件编写的软件应满足用户的要求至少应满足以下3个要求: 至少应满足以下 个要求: 个要求对于所有正确的输入能产生正确的结果。 对于所有正确的输入能产生正确的结果。 对于所有不正确的输入能给出合理的提示信息。 对于所有不正确的输入能给出合理的提示信息。 程序运行遇到错误后能终止程序的运行。 程序运行遇到错误后能终止程序的运行。
较高要求包括: 较高要求包括:硬件故障情况下,程序能继续运行或合理终止 掉电 硬盘损坏, 掉电、 硬件故障情况下,程序能继续运行或合理终止(掉电、硬盘损坏,网 络故障等) 络故障等 系统软件故障情况下,程序能继续运行或合理终止(操作系统 操作系统, 系统软件故障情况下,程序能继续运行或合理终止 操作系统,数据 库管理系统等) 库管理系统等
对于商业和工业应用的实用化系统应能满足较高要求, 对于商业和工业应用的实用化系统应能满足较高要求,比如 电子商务系统,医疗系统,工业控制系统等。 电子商务系统,医疗系统,工业控制系统等。
Page 3
C++程序设计
1.3正确的实现软件 正确的实现软件编写的程序应该尽量减少错误程序开发过程中会出现4种错误: 程序开发过程中会出现 种错误: 种错误编译错误(compile-time errors)。编译器发现的错误,说 编译错误 。编译器发现的错误, 明程序代码不符合计算机语言规定的语法标准。 明程序代码不符合计算机语言规定的语法标准。 链接错误(link-time errors)。链接器发现的错误,一般是 链接错误 。链接器发现的错误, 函数实现与函数声明不对应,全局变量未定义, 函数实现与函数声明不对应,全局变量未定义,未链接 需要的库等。 需要的库等。 运行时错误(run-time errors)。一般表示与硬件或系统软 运行时错误 。 件发生冲突,比如网络中断,硬盘耗尽,硬件中断错误, 件发生冲突,比如网络中断,硬盘耗尽,硬件中断错误, 软件中断错误,资源读写竞争, 等等。 软件中断错误,资源读写竞争,除0等等。 等等 逻辑错误(logic errors)。程序编写中有 逻辑错误 。程序编写中有bug,程序不能得 , 到正确的计算结果。 到正确的计算结果。Page 4
C++程序设计
1.4如何减少错误 如何减少错误一般原则通过良好的代码组织减少错误,减小错误的影响范围 充分利 通过良
好的代码组织减少错误,减小错误的影响范围(充分利 用函数和类实现封装,如果出现错误, 用函数和类实现封装,如果出现错误,尽量把错误的范围限 制在封装的范围内,不波及到程序的其它部分) 制在封装的范围内,不波及到程序的其它部分 通过调试和测试消除错误。 通过调试和测试消除错误。
通过以上方法尽量减少错误,并使得未发现和未纠正 的错误不会严重影响程序的正常运行。 编写正确的程序虽然需要大量的实践经验,但是从一 开始就进行良好的训练更重要。
Page 5
C++程序设计
2解决错误 解决错误解决编译错误编译错一般都是语法错误,比如 编译错一般都是语法错误,比如:写掉了行尾的;号 写掉了行尾的 号 把英文的;号写成了汉字的 号写成了汉字的; 把英文的 号写成了汉字的;号 括号没有配对 类型名称,变量名称,函数名称,头文件名称键入错了等等。 类型名称,变量名称,函数名称,头文件名称键入错了等等。
一般情况下,编译器给出的编译错误都是描述性的, 一般情况下,编译器给出的编译错误都是描述性的,根据其 描述的内容查找到指定的代码行纠正语法错误就可以了。 描述的内容查找到指定的代码行纠正语法错误就可以了。 一般总是先解决第一个编译错指定的代码行,然后再编译。 一般总是先解决第一个编译错指定的代码行,然后再编译。 如果还有编译错,以此循环,直至消除全部编译错。 如果还有编译错,以此循环,直至消除全部编译错。
C++程序设计
2解决错误 解决错误解决链接错误链接错误的原因很少,一般就 种情况 种情况: 链接错误的原因很少,一般就3种情况:函数定义和函数声明不对应(一般是因为函数名键入错了 函数定义和函数声明不对应 一般是因为函数名键入错了) 一般是因为函数名键入错了 全局变量进行了声明和使用,但没有定义(前面加 前面加extern是 全局变量进行了声明和使用,但没有定义 前面加 是 全局变量的声明,而不是定义) 全局变量的声明,而不是定义 没有链接需要的库(标准库是自动链接的 但其它的库, 标准库是自动链接的, 没有链接需要的库 标准库是自动链接的,但其它的库,比 如提供网络通信功能的库就需要告诉IDE库的名称和路径 如提供网络通信功能的库就需要告诉 库的名称和路径 才能实现链接) 才能实现链接
C++程序设计
2解决错误 解决错误解决运行时错误通过一套完整的错误检查, 通过一套完整的错误检查,报告与处理机制来解决 运行时错误
解决逻辑错误通过调试和测试手段来解决逻辑错误
C++程序设计
3函数的防错设计 函数的防错设计函数设计的基本原则: 函数负责检查和报告
错误; 函数的调用者负责处理错误 报告错误的4种方式函数的返回值 全局的错误变量; 全局的错误变量; assert宏 宏 异常Page 9
C++程序设计
3.1报告错误 报告错误(Error report) 报告错误通过返回值报告错误返回整型和指针类型的函数可以通过返回值报告 错误整型返回值 返回负数表示函数执行中出现了运行时错误, 返回负数表示函数执行中出现了运行时错误,不能 得到预期的结果。 得到预期的结果。 各种负返回值应该定义为符号常量或const常量。 常量。 各种负返回值应该定义为符号常量或 常量 指针返回值 返回空指针表示函数执行中遇到了错误或没有执行 函数功能。 函数功能。
Page 10
C++程序设计
3.1报告错误 报告错误(Error report) 报告错误示例:const int TheFirstError = -1; const int TheSecondError = -2; const int TheThirdError = -3; ...... int Func( argument list ) { ...... if( ... ) return TheFirstError; .... if( ... ) return TheSecondError; ...... return 0; }
Page 11
C++程序设计
3.1报告错误 报告错误(Error report) 报告错误通过全局的错误变量浮点型的返回值任何一个浮点型的值都是合法的结果, 任何一个浮点型的值都是合法的结果,找不到一个可以表示函数执 行错误的值作为返回值。 行错误的值作为返回值。 使用全局的errno变量报告函数执行出现运行时错误。 使用全局的 变量报告函数执行出现运行时错误。 变量报告函数执行出现运行时错误
全局变量errno 全局变量C标准库的头文件 标准库的头文件<errno.h>中声明了一个全局变量 中声明了一个全局变量errno存储错误 标准库的头文件 中声明了一个全局变量 存储错误 代码。 代码。 一些库函数通过给errno赋值来产生函数执行出错的信号。在调用 赋值来产生函数执行出错的信号。 一些库函数通过给 赋值来产生函数执行出错的信号 函数后,可以检查errno的值是否为 检查函数执行是否正常。 的值是否为0检查函数执行是否正常 函数后,可以检查 的值是否为 检查函数执行是否正常。 在调用前需要将errno清0,因为这是一个全局变量,函数只管修改 在调用前需要将 清 ,因为这是一个全局变量, 它的值,而不管复原它。 它的值,而不管复原它。
Page 12
C++程序设计
3.1报告错误 报告错误(Error report) 报告错误errno = 0; y = sqrt(x); if( errno != 0 ){ fprintf( stderr, "sqrt error, program terminated.\n"); exit( -1 ); } 也可以执行perror函数输出错误信息,该函数原型为 函数输出错误信息, 也可以执行 函数输出错误信息 void perror( const char * ); 该函数向标准错误流输出 最后是errno相关的错误信息 参数字符串 一个分号 一个空格 最后是 相关的错误信息 errno = 0; y = sqrt(x); if( errno != 0 ){ perror( "sqrt error"); exit( -1 ); }
自定义的函数也可以使用这个全局变量并定义自己的错误码。 自定义的函数也可以使用这个全局变量并定义自己的错误码。Page 13
C++程序设计
3.1报告错误 报告错误(Error report) 报告错误通过assert宏assert宏声明在<assert.h>中( C++是<cassert> ) 宏声明在 中 是 其原型为 void assert( int expression ); 带一个参数,这个参数是一个正常情况一定为真的表达式。 带一个参数,这个参数是一个正常情况一定为真的表达式。
每次执行到这个函数,就检查参数表达式的值,如果该值为假(0), , 每次执行到这个函数,就检查参数表达式的值,如果该值为假 则向stderr输出一行错误信息, 并调用 输出一行错误信息, 函数终止程序执行。 则向 输出一行错误信息 并调用abort函数终止程序执行。 函数终止程序执行 显示的错误信息包括参数表达式,源文件名和代码行号。 显示的错误信息包括参数表达式,源文件名和代码行号。如: char *p = new char[N+1]; assert( p ); 该代码保证p不为空 不为空。 该代码保证 不为空。Page 14
C++程序设计
3.1报告错误 报告错误(Error report) 报告错误通过异常报告错误C++中,如果函数执行过程中发生错误,则在发生 中 如果函数执行过程中发生错误, 异常(throw exception),函数不 错误的地方抛出一个异常 , 错误的地方抛出一个异常 再往下执行。 再往下执行。 函数的调用者通过try-catch块捕获可能发生的异常 块捕获可能发生的异常 函数的调用者通过 并进行相应处理。 并进行相应处理。
Page 15