您的位置:首页 > 编程语言 > C语言/C++

C语言利用setjmp和longjmp实现异常处理

2017-07-28 15:23 429 查看
C语言相比C++和Java没有提供异常处理机制,比如 try / catch 机制,但是我们可以使用C语言中的 setjmp / longjmp 方法来模拟出一种类似的异常处理机制。

这两个函数定义在 setjmp.h 头文件中, C文档中对于这两个方法的解释如下:

int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);

setjmp()  and  longjmp(3) are useful for dealing with errors and interrupts encountered in a low-level subroutine of a program.

setjmp() saves the stack context/environment in env for later use by longjmp(3).
The stack context will be invalidated if the function which called setjmp() returns.

longjmp() restores the environment saved by the last call of setjmp(3) with the corresponding env argument.
After longjmp() is completed, program execution continues as  if the corresponding call of setjmp(3) had just returned the value val.
longjmp() cannot cause 0 to be returned.  If longjmp() is invoked with a second argument of 0, 1 will be returned instead.

大致的意思是说,第一次调用 setjmp 会返回0 ,程序会记录下当前的位置和调用环境等信息,等程序出错时,我们调用 longjmp, 并设置第二个参数为非0的整数, 这时程序会终止后面的代码,直接跳转到第一次调用 setjmp 的位置,此时setjmp 的返回值不再是0, 而是返回调用 longjmp 设置的第二个参数。下面用一个简单的代码来演示:

#include <stdio.h>
#include <setjmp.h>

#define DIVIDER_CAN_NOT_BE_ZERO 1

jmp_buf env_buf;

//实现简单的除法
float divide(int a, int b)
{
if (b == 0)
{
longjmp(env_buf, DIVIDER_CAN_NOT_BE_ZERO);
}

return (float)a / b;
}

int main()
{
int errnum = setjmp(env_buf);

if (errnum == 0)
{
//正常的逻辑
printf("a / b = %f\n", divide(3, 0));
return 0;
}
else
{
//出错时的逻辑
if (errnum == DIVIDER_CAN_NOT_BE_ZERO)
{
printf("出错啦,除数不能为0\n");
printf("其他的处理...\n");
}
else
{
printf("其他错误...\n");
}

return errnum;
}
}


程序从main函数进入,第一次调用 setjmp 返回 0, 此时程序进入正常逻辑分支, 调用 divide 方法,由于除数为0,此时divide方法中调用了 longjmp, 并传入了一个错误码,longjmp打断了函数的继续执行,回到第一次调用 setjmp 的位置继续运行,此时setjmp 返回调用 longjmp 设置的错误码, 进入出错的逻辑,这就类似用 longjmp 函数抛出错误, 用 setjmp 捕获错误并处理,实现错误的集中统一处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息