用C语言实现try-catch/try-except功能
本文拟用C语言中的 signal
函数、siglongjmp
函数来实现类似python中的 try - except 功能或是C++中的 try - catch 功能。
一、函数说明
用C语言实现C++的try-catch功能或类似python的try-except功能,主要依赖C标准库中的signal
、siglongjmp
和__sigsetjmp
三个函数。
signal(int signum, sighandler_t handler)
,用于注册异常信号,只有注册过的异常信号类型,才能捕获到。参数signum
是要注册的信号(异常);参数handler
则是对应信号的处理函数;
__sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask)
,用于存储环境信息,也即是将调用该函数处,所在时刻的环境信息写入变量env
中;注意,该函数第一次调用时,其返回值为
0
0
0。
siglongjmp (struct __jmp_buf_tag __env[1], int __val)
,该函数实现跨函数的跳转,它将跳转到第一次调用函数__sigsetjmp
所在的位置,并将参数__val
作为__sigsetjmp
的返回值。
二、跳转说明
下面以第三部分的实例代码,简述一下整个C语言版try-catch的跳转流程,如下图:
三、代码示例
如下代码示例,通过signal
、siglongjmp
和__sigsetjmp
三个函数实现了C语言下的try-catchg功能。我们通过在测试函数test_fun 中写入不同的异常,来测试代码功能。
未在test_fun中写入异常代码时,函数正常返回
0
0
0,如下图:
当在test_fun中加入一行,除
0
0
0 的代码时,函数返回
−
1
-1
−1,结果如下图:
当在test_fun中加入一行越界写的代码时,运行结果返回
−
1
-1
−1,如下图:
以下是整个示例的完整代码。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <setjmp.h>
#include <signal.h>
jmp_buf env; // 定义结构体变量env,用来存储环境信息
/**@brief 信号处理函数 */
void sig_handle(int sig) { siglongjmp(env,1); }
/**@brief 注册信号捕捉 */
void sig_init(void)
{
signal(SIGABRT,sig_handle);
signal(SIGFPE,sig_handle);
signal(SIGILL,sig_handle);
signal(SIGINT,sig_handle);
signal(SIGSEGV,sig_handle);
signal(SIGTERM,sig_handle);
}
/**@brief 注销信号捕捉 */
void sig_reset(void)
{
signal(SIGABRT,SIG_DFL);
signal(SIGFPE,SIG_DFL);
signal(SIGILL,SIG_DFL);
signal(SIGINT,SIG_DFL);
signal(SIGSEGV,SIG_DFL);
signal(SIGTERM,SIG_DFL);
}
/**@brief 测试函数 */
static int test_fun(void)
{
int i = 0;
int a[3] = {1,2,3};
printf("in test fun.\n");
// i = 1/0; // 除0错误
// a[3] = 2; // 越界写异常
return 0; // 正常结束返回0
}
/**@brief 主函数 */
void main(void)
{
int err_num = 0; // 定义异常值,初始值为0;
sig_init(); // 注册信号捕获
//
switch (__sigsetjmp(env,1))
{
case 0: // 正常运行时的case
err_num = test_fun();
break;
default: // 当case 0中test_fun出现异常时,跳转到default
err_num = -1;
break;
}
sig_reset(); // 信号捕获注销
printf("err_num = %d\n",err_num); // 正常返回打印0,捕获异常打印 -1
}