当前位置:文档之家› C异常处理实现

C异常处理实现

C异常处理实现
C异常处理实现

C异常处理实现: setjmp和longjmp

此文为internet上选摘,过后我会用自己的理解补充此文。

------------

将对setjmp与longjmp的具体使用方法和适用的场合,进行一个非常全面的阐述。

另外请特别注意,setjmp函数与longjmp函数总是组合起来使用,它们是紧密相关的一对操作,只有将它们结合起来使用,才能达到程序控制流有效转移的目的,才能按照程序员的预先设计的意图,去实现对程序中可能出现的异常进行集中处理。

与goto语句的作用类似,它能实现本地的跳转

这种情况容易理解,不过还是列举出一个示例程序吧!如下:

void main( void )

{

int jmpret;

jmpret = setjmp( mark );

if( jmpret == 0 )

{

// 其它代码的执行

// 判断程序远行中,是否出现错误,如果有错误,则跳转!

if(1) longjmp(mark, 1);

// 其它代码的执行

// 判断程序远行中,是否出现错误,如果有错误,则跳转!

if(2) longjmp(mark, 2);

// 其它代码的执行

// 判断程序远行中,是否出现错误,如果有错误,则跳转!

if(-1) longjmp(mark, -1);

// 其它代码的执行

}

else

{

// 错误处理模块

switch (jmpret)

{

case 1:

printf( "Error 1"n");

break;

case 2:

printf( "Error 2"n");

break;

case 3:

printf( "Error 3"n");

break;

default :

printf( "Unknown Error");

break;

}

exit(0);

}

return;

}

上面的例程非常地简单,其中程序中使用到了异常处理的机制,这使得程序的代码非常紧凑、清晰,易于理解。在程序运行过程中,当异常情况出现后,控制流是进行了一个本地跳转(进入到异常处理的代码模块,是在同一个函数的内部),这种情况其实也可以用goto语句来予以很好的实现,但是,显然setjmp与longjmp的方式,更为严谨一些,也更为友善。程序的执行流如图17-1所示。

setjmp与longjmp相结合,实现程序的非本地的跳转

呵呵!这就是goto语句所不能实现的。也正因为如此,所以才说在C语言中,setjmp与longjmp 相结合的方式,它提供了真正意义上的异常处理机制。其实上一篇文章中的那个例程,已经演示了longjmp函数的非本地跳转的场景。这里为了更清晰演示本地跳转与非本地跳转,这两者之间的区别,我们在上面刚才的那个例程基础上,进行很小的一点改动,代码如下:

void Func1()

{

// 其它代码的执行

// 判断程序远行中,是否出现错误,如果有错误,则跳转!

if(1) longjmp(mark, 1);

}

void Func2()

{

// 其它代码的执行

// 判断程序远行中,是否出现错误,如果有错误,则跳转!if(2) longjmp(mark, 2);

}

void Func3()

{

// 其它代码的执行

// 判断程序远行中,是否出现错误,如果有错误,则跳转!if(-1) longjmp(mark, -1);

}

void main( void )

{

int jmpret;

jmpret = setjmp( mark );

if( jmpret == 0 )

{

// 其它代码的执行

// 下面的这些函数执行过程中,有可能出现异常

Func1();

Func2();

Func3();

// 其它代码的执行

}

else

{

// 错误处理模块

switch (jmpret)

{

case 1:

printf( "Error 1"n");

break;

case 2:

printf( "Error 2"n");

break;

case 3:

printf( "Error 3"n");

break;

default :

printf( "Unknown Error");

break;

}

exit(0);

}

return;

}

回顾一下,这与C++中提供的异常处理模型是不是很相近。异常的传递是可以跨越一个或多个函数。这的确为C程序员提供了一种较完善的异常处理编程的机制或手段。

setjmp和longjmp使用时,需要特别注意的事情

1、setjmp与longjmp结合使用时,它们必须有严格的先后执行顺序,也即先调用setjmp函数,之后再调用longjmp函数,以恢复到先前被保存的“程序执行点”。否则,如果在setjmp 调用之前,执行longjmp函数,将导致程序的执行流变的不可预测,很容易导致程序崩溃而退出。请看示例程序,代码如下:

class Test

{

public:

Test()

~Test()

}obj;

//注意,上面声明了一个全局变量obj

void main( void )

{

int jmpret;

// 注意,这里将会导致程序崩溃,无条件退出

Func1();

while(1);

jmpret = setjmp( mark );

if( jmpret == 0 )

{

// 其它代码的执行

// 下面的这些函数执行过程中,有可能出现异常

Func1();

Func2();

Func3();

// 其它代码的执行

}

else

{

// 错误处理模块

switch (jmpret)

{

case 1:

printf( "Error 1"n");

break;

case 2:

printf( "Error 2"n");

break;

case 3:

printf( "Error 3"n");

break;

default :

printf( "Unknown Error");

break;

}

exit(0);

}

return;

}

上面的程序运行结果,如下:

构造对象

Press any key to continue

的确,上面程序崩溃了,由于在Func1()函数内,调用了longjmp,但此时程序还没有调用setjmp来保存一个程序执行点。因此,程序的执行流变的不可预测。这样导致的程序后果是非常严重的,例如说,上面的程序中,有一个对象被构造了,但程序崩溃退出时,它的析构函数并没有被系统来调用,得以清除一些必要的资源。所以这样的程序是非常危险的。(另外请注意,上面的程序是一个C++程序,所以大家演示并测试这个例程时,把源文件的扩展名改为xxx.cpp)。

2、除了要求先调用setjmp函数,之后再调用longjmp函数(也即longjmp必须有对应的setjmp函数)之外。另外,还有一个很重要的规则,那就是longjmp的调用是有一定域范围要求的。这未免太抽象了,还是先看一个示例,如下:

int Sub_Func()

{

int jmpret, be_modify;

be_modify = 0;

jmpret = setjmp( mark );

if( jmpret == 0 )

{

// 其它代码的执行

}

else

{

// 错误处理模块

switch (jmpret)

{

case 1:

printf( "Error 1"n");

break;

case 2:

printf( "Error 2"n");

break;

case 3:

printf( "Error 3"n");

break;

default :

printf( "Unknown Error");

break;

}

//注意这一语句,程序有条件地退出

if (be_modify==0) exit(0);

}

return jmpret;

}

void main( void )

{

Sub_Func();

// 注意,虽然longjmp的调用是在setjmp之后,但是它超出了setjmp的作用范围。longjmp(mark, 1);

}

如果你运行或调试(单步跟踪)一下上面程序,发现它真是挺神奇的,居然longjmp执行时,程序还能够返回到setjmp的执行点,程序正常退出。但是这就说明了上面的这个例程的没有问题吗?我们对这个程序小改一下,如下:

int Sub_Func()

{

// 注意,这里改动了一点

int be_modify, jmpret;

be_modify = 0;

jmpret = setjmp( mark );

if( jmpret == 0 )

{

// 其它代码的执行

}

else

{

// 错误处理模块

switch (jmpret)

{

case 1:

printf( "Error 1"n");

break;

case 2:

printf( "Error 2"n");

break;

case 3:

printf( "Error 3"n");

break;

default :

printf( "Unknown Error");

break;

}

//注意这一语句,程序有条件地退出

if (be_modify==0) exit(0);

}

return jmpret;

}

void main( void )

{

Sub_Func();

// 注意,虽然longjmp的调用是在setjmp之后,但是它超出了setjmp的作用范围。longjmp(mark, 1);

}

运行或调试(单步跟踪)上面的程序,发现它崩溃了,为什么?这就是因为,“在调用setjmp的函数返回之前,调用longjmp,否则结果不可预料”(这在上一篇文章中已经提到过,MSDN中做了特别的说明)。为什么这样做会导致不可预料?其实仔细想想,原因也很简单,那就是因为,当setjmp函数调用时,它保存的程序执行点环境,只应该在当前的函数作用域以内(或以后)才会有效。如果函数返回到了上层(或更上层)的函数环境中,那么setjmp保存的程序的环境也将会无效,因为堆栈中的数据此时将可能发生覆盖,所以当然会导致不可预料的执行后果。

3、不要假象寄存器类型的变量将总会保持不变。在调用longjmp之后,通过setjmp 所返回的控制流中,例程中寄存器类型的变量将不会被恢复。(MSDN中做了特别的说明,上一篇文章中,这也已经提到过)。寄存器类型的变量,是指为了提高程序的运行效率,变量不被保存在内存中,而是直接被保存在寄存器中。寄存器类型的变量一般都是临时变量,在C语言中,通过register定义,或直接嵌入汇编代码的程序。这种类型的变量一般很少采用,所以在使用setjmp和longjmp时,基本上不用考虑到这一点。

4、MSDN中还做了特别的说明,“在C+ +程序中,小心对setjmp和longjmp的使用,因为setjmp和longjmp并不能很好地支持C++中面向对象的语义。因此在C++程序中,使用C++提供的异常处理机制将会更加安全。”虽然说C++能非常好的兼容C,但是这并非是100%的完全兼容。例如,这里就是一个很好的例子,在C++ 程序中,它不能很好地与setjmp和longjmp和平共处。在后面的一些文章中,有关专门讨论C++如何兼容支持C语言中的异常处理机制时,会做详细深入的研究,这里暂且跳过

异常处理练习题

异常处理练习题 一、选择题 中用来抛出异常的关键字是 A、try B、catch C、throw D、finally 2.关于异常,下列说法正确的是 A、异常是一种对象 B、一旦程序运行,异常将被创建 C、为了保证程序运行速度,要尽量避免异常控制 D、以上说法都不对 3.()类是所有异常类的父类。 A、Throwable B、Error C、Exception D、AWTError 语言中,下列哪一子句是异常处理的出口 A、try{…}子句 B、catch{…}子句 C、finally{…}子句 D、以上说法都不对 5.下列程序的执行,说法正确的是 public class MultiCatch { public static void main(String args[]) { try { int a=; int b=42/a; int c[]={1}; c[42]=99; } catch(ArithmeticException e) { 除0异常:”+e); } catch(ArrayIndexOutOfBoundsException e) { 数组超越边界异常:”+e); } } } A、程序将输出第15行的异常信息 B、程序第10行出错 C、程序将输出“b=42” D、程序将输出第15和19行的异常信息 6.下列程序的执行,说法正确的是 class ExMulti { static void procedure() { try {

int c[]={1}; c[42]=99; } catch(ArrayIndexOutOfBoundsException e) { 数组超越界限异常:”+e); } } public static void main(String args[]) { try { procedure(); int a=; int b=42/a; } catch(ArithmeticException e) { 除0异常:”+e); } } } A、程序只输出第12行的异常信息 B、程序只输出第26行的异常信息 C、程序将不输出异常信息 D、程序将输出第12行和第26行的异常信息 7.下面程序抛出了一个“异常”并捕捉它。请在横线处填入适当内容完成程序。class TrowsDemo { static void procedure() throws IllegalAccessException { procedure”); throw____new___IllegalAccessException(“demo”); } public static void main(String args[]) { try { procedure(); } ___catch (IllegalAccessException e)________ { 捕获:”+e); } } 8.对于catch子句的排列,下列哪种是正确的( ) A、父类在先,子类在后 B、子类在先,父类在后

C异常处理(精)

#include "stdafx.h" #include #include #include // 内存泄露检测机制 #define _CRTDBG_MAP_ALLOC #ifdef _DEBUG #define new new(_NORMAL_BLOCK, __FILE__, __LINE__ #endif // 自定义异常类 class MyExcepction { public: // 构造函数,参数为错误代码 MyExcepction(int errorId { // 输出构造函数被调用信息 std::cout << "MyExcepction is called" << std::endl; m_errorId = errorId; } // 拷贝构造函数 MyExcepction( MyExcepction& myExp { // 输出拷贝构造函数被调用信息 std::cout << "copy construct is called" << std::endl; this->m_errorId = myExp.m_errorId; }

~MyExcepction( { // 输出析构函数被调用信息 std::cout << "~MyExcepction is called" << std::endl; } // 获取错误码 int getErrorId( { return m_errorId; } private: // 错误码 int m_errorId; }; int main(int argc, char* argv[] { // 内存泄露检测机制 _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ; // 可以改变错误码,以便抛出不同的异常进行测试 int throwErrorCode = 110; std::cout << " input test code :" << std::endl; std::cin >> throwErrorCode; try { if ( throwErrorCode == 110 { MyExcepction myStru(110;

C++异常处理机制全解

C++异常处理机制全解 ▌异常处理(Exception handling) ●返回一个错误码进行异常处理(C语言): 例: boolfunc(float a, float b, float& c){ if(b==0){ return false; } c=a/b; return true; } int main() { float a=10; float b=0; float c=0; bool result=func(a, b, c); if(!result){ cout<<"The func fails!"<

int main() { float a=10; float b=0; float c=0; try{ //测试条件; func(a, b, c); //func1(); //func2(); } catch(const char* str){ //捕获异常信息; cout<

C 中异常处理的语法 try catch throw - 大漠一抹云 樊书林 - 博客园

C 中异常处理的语法try catch throw - 大漠一抹云樊书林 - 博客园 C++中异常处理的语法。 关键字 1、try 2、catch 3、throw 其中关键字try表示定义一个受到监控、受到保护的程序代码块;关键字catch与try遥相呼应,定义当try block(受监控的程序块)出现异常时,错误处理的程序模块,并且每个catch block都带一个参数(类似于函数定义时的数那样),这个参数的数据类型用于异常对象的数据类型进行匹配;而throw 则是检测到一个异常错误发生后向 外抛出一个异常事件,通知对应的catch程序块执行对应的错误处理。 语法

1、还是给一个例子吧!如下: int main() { cout << "In main." << endl; //定义一个try block,它是用一对花括号{}所括起来的块作用域的代码块 try { cout << "在try block 中, 准备抛出一个异常." << endl; //这里抛出一个异常(其中异常对象的数据类型是int,值为1) //由于在try block中的代码是受到监控保护的,所以抛出异常后,程序的 //控制流便转到随后的catch block中 throw 1; cout << "在try block 中, 由于前面抛出了一个异常,因此这里的代码是不会得以执行到的" << endl; } //这里必须相对应地,至少定义一个catch block,同样

它也是用花括号括起来的 catch( int& value ) { cout << "在catch block 中, 处理异常错误。异常对象value的值为:"<< value << endl; } cout << "Back in main. Execution resumes here." << endl; return 0; } 2、语法很简单吧!的确如此。另外一个try block可以有多个对应的catch block,可为什么要多个catch block呢?这是因为每个catch block匹配一种类型的异常错误对象的处理,多个catch block呢就可以针对不同的异常错误类型分别处理。毕竟异常错误也是分级别的呀!有致命的、有一般的、有警告的,甚至还有的只是事件通知。例子如下: int main() {

java异常处理试题及答案

异常处理练习题 一、选择题 1.java中用来抛出异常的关键字是 (C) A、try B、catch C、throw D、finally 2.关于异常,下列说法正确的是(A) A、异常是一种对象 B、一旦程序运行,异常将被创建 C、为了保证程序运行速度,要尽量避免异常控制 D、以上说法都丌对 3.(A)类是所有异常类的父类。 A、Throwable B、Error C、Exception D、AWTError 4.java语言中,下列哪一子句是异常处理的出口(C) A、try{…}子句 B、catch{…}子句 C、finally{…}子句 D、以上说法都丌对 5.下列程序的执行,说法错误的是 (C) public class MultiCatch { public static void main(String args[]) { try { int a=args.length; int b=42/a; int c[]={1}; c[42]=99; System.out.println(“b=”+b); } catch(ArithmeticException e) { System.out.println(“除0异常:”+e); } catch(ArrayIndexOutOfBoundsException e) { System.out.println(“数组超越边界异常:”+e); } } } A、程序将输出第15行的异常信息 B、程序第10行出错 C、程序将输出“b=42”

D、程序将输出第15和19行的异常信息 6.下列程序的执行,说法正确的是(D) class ExMulti { static void procedure() { try { int c[]={1}; c[42]=99; } catch(ArrayIndexOutOfBoundsException e) { System.out.println(“数组超越界限异常:”+e); } } public static void main(String args[]) { try { procedure(); int a=args.length; int b=42/a; System.out.println(“b=”+b); } catch(ArithmeticException e) { System.out.println(“除0异常:”+e); } } } A、程序只输出第12行的异常信息 B、程序只输出第26行的异常信息 C、程序将不输出异常信息 D、程序将输出第12行和第26行的异常信息 7.下面程序抛出了一个“异常”并捕捉它。请在横线处填入适当内容完成程序。class TrowsDemo { static void procedure() throws IllegalAccessExcepton { System.out.println(“inside procedure”); throw__new_____IllegalAccessException(“demo”);

异常处理

异常处理: (1) #include void main( ) { try { int a=8; double b=8.8; throw a Class exception { private: char *ch; Public: Exception(char *m) { ch=m; } V oid print( ) { cerr< Class exception { private: char *ch; Public: Exception(char *m) { ch=m; } V oid print( ) { cerr<

C异常处理实现(精)

C异常处理实现: setjmp和longjmp 此文为internet上选摘,过后我会用自己的理解补充此文。 ------------ 将对setjmp与longjmp的具体使用方法和适用的场合,进行一个非常全面的阐述。 另外请特别注意,setjmp函数与longjmp函数总是组合起来使用,它们是紧密相关的一对操作,只有将它们结合起来使用,才能达到程序控制流有效转移的目的,才能按照程序员的预先设计的意图,去实现对程序中可能出现的异常进行集中处理。 与goto语句的作用类似,它能实现本地的跳转 这种情况容易理解,不过还是列举出一个示例程序吧!如下: void main( void ) { int jmpret; jmpret = setjmp( mark ); if( jmpret == 0 ) { // 其它代码的执行 // 判断程序远行中,是否出现错误,如果有错误,则跳转! if(1) longjmp(mark, 1); // 其它代码的执行 // 判断程序远行中,是否出现错误,如果有错误,则跳转! if(2) longjmp(mark, 2); // 其它代码的执行 // 判断程序远行中,是否出现错误,如果有错误,则跳转! if(-1) longjmp(mark, -1); // 其它代码的执行 } else { // 错误处理模块 switch (jmpret) { case 1: printf( "Error 1"n");

break; case 2: printf( "Error 2"n"); break; case 3: printf( "Error 3"n"); break; default : printf( "Unknown Error"); break; } exit(0); } return; } 上面的例程非常地简单,其中程序中使用到了异常处理的机制,这使得程序的代码非常紧凑、清晰,易于理解。在程序运行过程中,当异常情况出现后,控制流是进行了一个本地跳转(进入到异常处理的代码模块,是在同一个函数的内部),这种情况其实也可以用goto语句来予以很好的实现,但是,显然setjmp与longjmp的方式,更为严谨一些,也更为友善。程序的执行流如图17-1所示。

关于C++中的异常处理使用方法与技巧

1关于异常处理 1.1为什么要抛出异常 抛出异常的好处一是可以不干扰正常的返回值,另一个是调用者必须处理异常,而不像以前c语言返回一个整数型的错误码,调用者往往将它忽略了。 C++的异常处理确保当程序的执行流程离开一个作用域的时候,对于属于这个作用域的所有由构造函数建立起来的对象,它们的析构函数一定会被调用。 1.2捕获所有异常 有时候,程序员可能希望创建一个异常处理器,使其能够捕获所有类型的异常。用省略号代替异常处理器的参数列表就可以实现这一点: 由于省略号异常处理器能够捕获任何类型的异常,所以最好将它放在异常处理器列表的最后,从而避免架空它后面的异常处理器。 省略号异常处理器不允许接受任何参数,所以无法得到任何有关异常的信息,也无法知道异常的类型。它是一个“全能捕获者”。这种catch子句经常用于清理资源并重新抛出所捕获的异常。 1.3重新抛出异常 当需要释放某些资源时,例如网络连接或位于堆上的内存需要释放时,通常希望重新抛出一个异常。(详见本章后面的“资源管理”一节。)如果发生了异常,读者不必关心到底

是什么错误导致了异常的发生——只需要关闭以前打开的一个连接。此后,读者希望在某些更接近用户的语境(也就是说,在调用链中的更高层次)中对异常进行处理。在这种情况下,省略号异常处理器正符合这种的要求。这种处理方法,可以捕获所有异常,清理相关资源,然后重新抛出该异常,以使得其他地方的异常处理器能够处理该异常。在一个异常处理器内部,使 用不带参数的throw语句可以重新抛出异常: 与同一个try块相关的随后的catch子句仍然会被忽略—throw子句把这个异常传递给 位于更高一层语境中的异常处理器。另外,这个异常对象的所有信息都会保留,所以位于更高层语境中的捕获特定类型异常的异常处理器能够获取这个对象包含的所有信息。 1.4构造函数中的异常 C++规定构造函数抛出异常之后,对象将不被创建,析构函数也不会被执行,但已经创建成功的部分(比如一个类成员变量)会被部分逆序析构,不会产生内存泄漏。但有些资源需要在抛出异常前自己清理掉,比如打开成功的一个文件,最好关闭掉再抛出异常(虽然系统也会把这个资源回收),因为抛出异常之后析构函数不会被执行了。 (1)C++中通知对象构造失败的唯一方法那就是在构造函数中抛出异常;(这句话并不是说我们只有这个方法才能让上层知道构造函数失败,虽然构造函数没有返回值,我们完全可以在构造函数中传入一个引用值,然后在里面设置状态,运行完构造函数之后任然可以知道是否失败,但这种情况下面对象其实还是被构造出来的,只是里面有资源分配失败而已,并且析构函数还是会执行。这和我们构造失败不生成对象的初衷不符。)

C与C++中的异常处理

C与C++中的异常处理(1) 1.异常和标准C对它的支持 (前言略) 1.1异常分类 基于Dr. GUI的建议,我把我的第一个专栏投入到“程序异常”的系列上。我认识到,“exception”这个术语有些不明确并和上下文相关,尤其是C++标准异常(C++ standard exceptions)和Microsoft的结构化异常(structured exception handling)。不幸的的是,“异常”一词太常见了,随时出现在语言的标准和常见的编程文献中。因为不想创造一个新名词,所以我将尽力在此系列的各部分中明确我对“异常”的用法。 l Part 1概述通常意义上的异常的性质,和标准C库提供的处理它们的方法。 l Part 2纵览Microsoft对这些标准C库方法的扩展:专门的宏和结构化异常处理。 l Part 3及其余将致力于标准C++异常处理体系。 (C语言使用者可能在Part2后放弃,但我鼓励你坚持到底;我所提出的许多点子同样适用于C,虽然不是很直接。) 本质上看,程序异常是指出现了一些很少发生的或出乎意料的状态,通常显示了一个程序错误或要求一个必须提供的回应。不能满足这个回应经常造成程序功能削弱或死亡,有时导致整个系统和它一起down掉。不幸的是,试图使用传统的防护方法来编制健壮的代码经常只是将一个问题(意外崩溃)换成了另外一个问题(更混乱的设计和代码)。 太多的程序员认为这个交换抵不上程序意外崩溃时造成的烦恼,于是选择了生活在危险之中。认识到这一点后,C++标准增加了一个优雅并且基本上不可见的“异常体系”到语言中;就这样,这个方法产生了。如同我们在Part4的开始部分将要看到的,这个方法大部分情况下很成功,但在很微妙的情况下可能失败。 1.2异常的生命阶段 在这个系列里,我将展示C和C++处理异常体系运行于异常整个生命期的每一阶段时的不同之处: l阶段1:一个软件错误发生。这个错误也许产生于一个被底层驱动或内核映射为软件错误的硬件响应事件(如被0除)。 l阶段2:错误的原因和性质被一个异常对象携带。这个对象的类型可以简单的整数值到繁杂的C++类对象。 l阶段3:你的程序必须检测这个异常对象:或者轮询它的存在,或者由其主动上报。 l阶段4:检测代码必须决定如何处理异常。典型的方法分成三类。 a忽略异常对象,并期望别人处理它。 b在这个对象上干些什么,并还允许别人再继续处理它。 c获得异常的全部所有权。 l阶段5:既然异常已经处理了,程序通常恢复并继续执行。恢复分成两种: a恢复异常,从异常发生处继续执行。 b终止异常,从异常被处理处继续执行。 当在程序外面(由运行期库或操作系统)终止异常时,恢复经常是不可能的,程序将异常结束。 我故意忽略了硬件错误事件,因为它们完全是底层平台范围内的事。取而代之,我假定一些软件上的可检测错误已经发生,并产生了一个处于第一阶段的软件异常对象。

异常处理总结

异常处理总结 异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C开始,你也许已经知道如何用if...else...来控制异常了,也许是自发的,然而这种控制异常痛苦,同一个异常或者错误如果多个地方出现,那么你每个地方都要做相同处理,感觉相当的麻烦! Java语言在设计的当初就考虑到这些问题,提出异常处理的框架的方案,所有的异常都可以用一个类型来表示,不同类型的异常对应不同的子类异常(这里的异常包括错误概念),定义异常处理的规范,在1.4版本以后增加了异常链机制,从而便于跟踪异常!这是Java语言设计者的高明之处,也是Java语言中的一个难点,下面对Java异常知识的一个总结。 一、Java异常的基础知识 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。比如说,你的代码少了一个分号,那么运行出来结果是提示是错误https://www.doczj.com/doc/4e3910046.html,ng.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出https://www.doczj.com/doc/4e3910046.html,ng.ArithmeticException的异常。 有些异常需要做处理,有些则不需要捕获处理,后面会详细讲到。 天有不测风云,人有旦夕祸福,Java的程序代码也如此。在编程过程中,首先应当尽可能去避免错误和异常发生,对于不可避免、不可预测的情况则在考虑异常发生时如何处理。 Java中的异常用对象来表示。Java对异常的处理是按异常分类处理的,不同异常有不同的分类,每种异常都对应一个类型(class),每个异常都对应一个异常(类的)对象。 异常类从哪里来?有两个来源,一是Java语言本身定义的一些基本异常类型,二是用户通过继承Exception类或者其子类自己定义的异常。Exception 类及其子类是Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。 异常的对象从哪里来呢?有两个来源,一是Java运行时环境自动抛出系统生成的异常,而不管你是否愿意捕获和处理,它总要被抛出!比如除数为0的异常。二是程序员自己抛出的异常,这个异常可以是程序员自己定义的,也可以是Java语言中定义的,用throw 关键字抛出异常,这种异常常用来向调用者汇报异

c++异常处理习题答案

1. 概念填空题 1.1C++程序将可能发生异常的程序块放在try中,紧跟其后可放置若干个对应的catch,在前面所说的块中或块所调用的函数中应该有对应的throw,由它在不正常时抛出异常,如与某一条catch类型相匹配,则执行该语句。该语句执行完之后,如未退出程序,则执行catch后续语句。如没有匹配的语句,则交给C++标准库中的termanite处理。1.2 throw表达式的行为有些像函数的函数调用,而catch子句则有些像函数的函数定义。函数的调用和异常处理的主要区别在于:建立函数调用所需的信息在编译时已经获得,而异常处理机制要求运行时的支撑。对于函数,编译器知道在哪个调用点上函数被真正调用;而对于异常处理,异常是随机发生的,并沿调用链逆向查找异常处理子句,这与运行时的多态是不一样的。 2.简答题 2.1 C++中的异常处理机制意义,作用是什么? 2.2 当在try块中抛出异常后,程序最后是否回到try块中继续执行后面的语句? 2.3 什么叫抛出异常? catch可以获取什么异常参数?是根据异常参数的类型还是根据参数的值处理异常?请编写测试程序验证。 2.4 为什么C++要求资源的取得放在构造函数中,而资源的释放在析构函数中? 3.选择题 3.l 下列关于异常的叙述错误的是(A)。 A.编译错属于异常,可以抛出 B.运行错属于异常 C.硬件故障也可当异常抛出 D.只要是编程者认为是异常的都可当异常抛出 3.2下列叙述错误的是()。 A.throw语句须书写在时语句块中 B.throw语句必须在try语句块中直接运行或通过调用函数运行 C.一个程序中可以有try语句而没有throw语句 D.throw语句抛出的异常可以不被捕获 3.3 关于函数声明float fun(int a,int b)throw,下列叙述正确的是()。 A.表明函数抛出float类型异常 B.表明函数抛出任何类型异常 C.表明函数不抛出任何类型异常 D.表明函数实际抛出的异常 3.4下列叙述错误的是()。 A.catch(…)语句可捕获所有类型的异常 B.一个try语句可以有多个catch语句 C.catch(…)语句可以放在catch语句组的中间 D.程序中try语句与catch语句是一个整体,缺一不可 3.5下列程序运行结果为(A)。 #include using namespace std; class S{ public:

c++异常处理

C++中的异常(exception) 作者:张笑猛 原文出处:https://www.doczj.com/doc/4e3910046.html,/ 1.简介 1.1常用的错误处理方式 1.2 不常用的处理方式 1.3 异常 2. 异常的语法 2.1 try 2.2 catch 2.3 throw 2.4 函数声明 3. 异常使用技巧 3.1 异常是如何工作的 3.1.1 unwinding stack 3.1.2 RTTI 3.2 是否继承std::exception? 3.3 每个函数后面都要写throw()? 3.4 guard模式 3.5 构造函数和析构函数 3.6 什么时候使用异常 4.参考资料 1.简介 异常是由语言提供的运行时刻错误处理的一种方式。提到错误处理,即使不提到异常,你大概也已经有了丰富的经验,但是为了可以清楚的看到异常的好处,我们还是不妨来回顾一下常用的以及不常用的错误处理方式。 C++异常之网络知识 1.1 常用的错误处理方式 返回值。我们常用函数的返回值来标志成功或者失败,甚至是失败的原因。但是这种做法最大的问题是如果调用者不主动检查返回值也是可以被编译器接受的,你也奈何不了他:) 这在C++中还导致另外一个问题,就是重载函数不能只有不同的返回值,而有相同的参数表,因为如果调用者不检查返回值,则编译器会不知道应该调用哪个重载函数。当然这个问题与本文无关,我们暂且放下。只要谨记返回值可能被忽略的情况即可。

全局状态标志。例如系统调用使用的errno。返回值不同的是,全局状态标志可以让函数的接口(返回值、参数表)被充分利用。函数在退出前应该设置这个全局变量的值为成功或者失败(包括原因),而与返回值一样,它隐含的要求调用者要在调用后检查这个标志,这种约束实在是同样软弱。全局变量还导致了另外一个问题,就是多线程不安全:如果多个线程同时为一个全局变量赋值,则调用者在检查这个标志的时候一定会非常迷惑。如果希望线程安全,可以参照errno 的解决办法,它是线程安全的。 1.2 不常用的处理方式 setjmp()/longjmp()。可以认为它们是远程的goto语句。根据我的经验,它们好象确实不常被用到,也许是多少破坏了结构化编程风格的原因吧。在C++中,应该是更加的不要用它们,因为致命的弱点是longjmp()虽然会unwinding stack (这个词后面再说),但是不会调用栈中对象的析构函数--够致命吧。对于不同的编译器,可能可以通过加某个编译开关来解决这个问题,但太不通用了,会导致程序很难移植。 1.3 异常 现在我们再来看看异常能解决什么问题。对于返回值和errno遇到的尴尬,对异常来说基本上不存在,如果你不捕获(catch)程序中抛出的异常,默认行为是导致abort()被调用,程序被终止(core dump)。因此你的函数如果抛出了异常,这个函数的调用者或者调用者的调用者,也就是在当前的call stack上,一定要有一个地方捕获这个异常。而对于setjmp()/longjmp()带来的栈上对象不被析构的问题对异常来说也是不存在的。那么它是否破坏了结构化(对于OO paradigms,也许应该说是破坏了流程?)呢?显然不是,有了异常之后你可以放心的只书写正确的逻辑,而将所有的错误处理归结到一个地方,这不是更好么? 综上所述,在C++中大概异常可以全面替代其它的错误处理方式了,可是如果代码中到处充斥着try/throw/catch也不是件好事,欲知异常的使用技巧,请保持耐心继续阅读:) 2. 异常的语法 在这里我们只讨论一些语法相关的问题。 2.1 try try总是与catch一同出现,伴随一个try语句,至少应该有一个catch()语句。try随后的block是可能抛出异常的地方。 2.2 catch

C++Java与C_的异常处理机制的比较研究

结 课 论 文 课程名称:C# 论文名称:C++、Java与C#异常处理机制的比较分析专业:计算机科学与技术 班级:计算机09-1班 姓名:姚伟 指导老师:王大阜 时间:2012年6月

C++、Java与C#异常处理机制的比较分析这个学期我选修了C+这门课,作为计算机专业的学生,本来想通过选修加上自己的学习,多熟悉一门语言。然而实际效果并没有预期那么好,大三重要的课程比较多,所以并没有花太多的时间在选修课上。王老师教学非常认真、负责,讲的内容也是比较具体、细致,上了几周课下来,结合自己已有的专业技能,对C#还是有了一定的认识和了解。 我们知道,C++延续了C的优点,再加上其很好的引入了面向对象程序设计,使C++迅速推广。由于它的可靠性,目前一些主流的大公司仍然热衷于C或C++。Java的出现可以说为面向对象程序设计思想引入了新的活力,近年来的热度已经超乎想象,比尔盖茨曾经这样评价:Java语言是长期以来最卓越的计算机程序设计语言。C++和Java是我的专业课程,并且现在主要用的还是这两种语言。以上并不代表我不喜欢C#,相反,通过半个学期的学习,我觉得C#是一门很了不起的语言。记得大二的时候,曾经自学过Delphi,学习C#后,深深的体会到C#要比Delphi 强很多,它不但延续了Delphi的一些特点,还结合了C++、Java 等程序设计理念。有人说,C#如今还不是很成熟,这便是它替代不了Java地位的首要原因。 上面是我对自己所学过三门编程语言的初步认识和了解,下面切入正题,分析一下C++、C#和Java异常处理机制的一些异同点。我们知道,一个健壮的程序必须考虑一定的容错能力,即

C++处理异常技巧-try,catch,throw,finally

这两天要处理一个异常的问题,刚好查了些相关的资料。在网上看到了一个不错的贴子,就转了过来,方便本人,以及来此旅游的朋友学习。源地址: https://www.doczj.com/doc/4e3910046.html,/Print.html?91983,1 异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制。 也许我们已经使用过异常,但是你会是一种习惯吗,不要老是想着当我打开一个文件的时候才用异常判断一下,我知道对你来说你喜欢用return value或者是print error message来做,你想过这样做会导致Memory Leak,系统退出,代码重复/难读,垃圾一堆…..吗?现在的软件已经是n*365*24小时的运行了,软件的健壮已经是一个很要考虑的时候了。 自序: 对写程序来说异常真的是很重要,一个稳健的代码不是靠返回Error Message/return Value来解决的,可是往往我们从C走过来,习惯了这样的方式。仅以本文献给今天将要来临的流星雨把,还好我能在今天白天把这写完,否则会是第4个通宵了;同时感谢Jeffrey大师,没有他的SEH理论这篇文章只能完成一半,而且所有SEH列子的构想都来自他的指导;另外要感谢Scott Meyers大师,我是看他的书长大的;还要感谢Adamc / Darwin / Julian ,当然还有Nick的Coffee 内容导读: (请打开文档结构图来读这篇文章。) 本文包括2个大的异常实现概念:C++的标准异常和SHE异常。 C++ 标准异常:也许我们了解过他,但你有考虑过,其实你根本不会使用,你不相信,那我问你:垃圾回收在C++中怎么实现?其实不需要实现,C++已经有了,但是你不会用,那么从<构造和析构中的异常抛出>开始看把。也许很高兴看到错误之后的Heap/Stack中对象被释放,可是如果没有呢?有或者试想一下一个能解决的错误,需要我们把整个程序Kill掉吗? 在C++标准异常中我向你推荐这几章:<使用异常规格编程> <构造和析构中的异常抛出> <使用析构函数防止资源泄漏> 以及一个深点的<抛出一个异常的行为> SHE异常:我要问你你是一个WIN32程序员吗?如果不是,那么也许你真的不需要看 这块内容了,SHE是Windows的结构化异常,每一个WIN32程序员都应该要掌握它。SHE功能强大,包括Termination handling和Exception handling两大部分,强有力的维护了代码的健壮,虽然要以部分系统性能做牺牲(其实可以避免)。在SHE中有大量的代码,已经在Win平台上测试过了。 这里要提一下:在__finally处理中编译器参与了绝大多数的工作,而Exception则是OS接管了几乎所有的工作,也许我没有提到的是:对__finally来说当遇到ExitThread/ExitProcess/abort等函数时,finally块不会被执行。另,我们的代码使用软件异常是比return error message好2**32的方法。

异常处理作业

第九章异常处理 一、选择题 1、无论是否发生异常,都需要执行( C ) A、try语句块 B、catch语句块 C、finally语句块 D、return语句 2、异常处理变量( C )。 A、应用public关键字 B、可以应用protected关键字 C、可以应用private关键字 D、只能在异常处理方法内使用。 3、通常的异常类是(A ) A、Exception B、exception C、CommonException D、ExceptionShare 4、异常产生的原因很多,常见的有(A )。 A、程序设计本身的错误 B、程序运行环境改变 C、软、硬件设置错误 D、以上都是 5、(C)是除0异常。 A、RuntimeException B、ClassCastException C、ArihmetticException D、ArrayIndexOutOfBoundException 6、下列描述中,对使用异常处理的原因描述错误的有( D ) A、将错误处理程序与正常程序流分开,增加程序的可读性 B、可以容易地指出异常在何处处理 C、减轻程序员处理异常的任务 D、增加语言的复杂机制 7、读下面代码,哪个选项是正确的( C ) import java.io.*; public class Test2{ public static void main(String []args)throws IOException{ i f(args[0]==”hello”) throw new IOException(); } } A、没有错误,程序编译正确 B、编译错误,不能够在main方法中抛出异常 C、编译错误,IOException是一个系统异常,不能够由application程序产生

相关主题
文本预览
相关文档 最新文档