标题:goto, setjmp/longjmp, try-catch 出处:Felix021 时间:Mon, 28 Dec 2009 15:48:39 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?1799 内容: 注:本文只是简单介绍这三个东西并对比一下其功能、差异,不讨论这些东西是否有存在的必要以及优劣。 · goto · setjmp, longjmp · try-catch 一、看看基本的使用 1. goto 这个比较简单,比较容易理解,只要设置一个行标就行了: 例子:int main () { int i = 0, sum; for (i = 0; i < 100; ++i) { sum += i; if (sum > 1000) goto JMP1; } JMP1: printf("%d\n", i); return 0; } 2. setjmp, longjmp goto用起来是简单,但是存在一个先天缺陷:只能在同一个函数内使用。 有时候我们写一个代码,有两三层的函数嵌套,想要返回的时候就比较囧。 这时候用setjmp和longjmp就很happy。 例子:#include jmp_buf jmpbuf1; void bar() { printf("Hi, I'm bar!\n"); longjmp(jmpbuf1, 1); } void foo() { printf("Hi, I'm foo!\n"); bar(); printf("Should never come here\n"); } int main () { int i = 0; i = setjmp(jmpbuf1); if (i == 0) { //setjmp第一次某个jmp_buf的时候返回0 foo(); } else { //否则返回longjmp给出的值 printf("i = %d\n", i); } return 0; } 输出是: Hi, I'm foo! Hi, I'm bar! i = 1 3. try-catch (在这里算是歪用了,呵呵) 这个是c++提供的语言特性,可以用于捕获throw语句抛出的异常,不仅可以在函数内使用,也可以跨函数~~ 例子:void bar() { printf("Hi, I'm bar!\n"); throw 1; } void foo() { printf("Hi, I'm foo!\n"); bar(); printf("Should never come here\n"); } int main () { try{ foo(); } catch(int i) { printf("i = %d\n", i); } return 0; } 输出是: Hi, I'm foo! Hi, I'm bar! i = 1 二、简单对比一下: · goto,使用简单方便,看起来比其他两个更容易一点(有行标),但是只能在函数内跳转; · setjmp和longjmp,稍微麻烦点,需要带个参数(jmp_buf,全局变量,或者传参),好处是可以跨函数跳转,且可以根据setjmp的返回值得知从何处跳转。还有一个小缺陷就是,因为需要先执行setjmp以后才可以跳转,所以可以跳转的地方有一定限制,也使得代码看起来有点不够清晰。 · try-catch,C++有C没有,看起来结构比较清晰,不需要带额外的参数,抛出不同的值(和类型)方便判断来源。 三、重点考察一个问题: 如果有一个class,比如class T { public: ~T() { printf("I'm dead >_<\n"); } }; 那么使用goto、setjmp或try-catch的时候是否存在问题? if (1) { T t1; goto JMP1; } JMP1: ; 有输出I'm dead >_< jmp_buf jmpbuf1; if (setjmp(jmpbuf1) == 0) { T t1; longjmp(jmpbuf1, 1); } else { ; } 无输出 try { T t1; throw 1; } catch(int i) { ; } 有输出I'm dead >_< 所以在使用这三个东西的时候,一定要特别注意,建议在C++里头不使用setjmp,以免查错无门... Generated by Bo-blog 2.1.0