linux c 实现try catch异常捕获

前言:

像如java这样的面相对象语言,异常处理机制让其代码更具健壮性,可以代码捕获到如算术异常,空指针异常等,俘获并能够在预知情况下进行相应处理。那么对于C而言,是否能实现其功能?

简要分析:

Linux有对线程或者进程退出时有一种信号量机制,而默认情况下,这种signal是系统自己处理的,而最统一的处理方式是exit,而至于什么原因退出这个完全取决于什么样的信号。至于linux下的这些signal多少,哪个对应什么情况自行查阅资料。Linux_c 的实现将通过宏来实现。

直接粗暴上代码吧:

 exception.h

#ifndef EXCEPTION_H_
#define EXCEPTION_H_

#include <setjmp.h>
#include <signal.h>

/* MANPROCSIGnals. */
#define MANPROCSIG_HUP  1 /* Hangup (POSIX). */
#define MANPROCSIG_INT  2 /* Interrupt (ANSI). */
#define MANPROCSIG_QUIT  3 /* Quit (POSIX). */
#define MANPROCSIG_ILL  4 /* Illegal instruction (ANSI). */
#define MANPROCSIG_TRAP  5 /* Trace trap (POSIX). */
#define MANPROCSIG_ABRT  6 /* Abort (ANSI). */
#define MANPROCSIG_IOT  6 /* IOT trap (4.2 BSD). */
#define MANPROCSIG_BUS  7 /* BUS error (4.2 BSD). */
#define MANPROCSIG_FPE  8 /* Floating-point exception (ANSI). */
#define MANPROCSIG_KILL  9 /* Kill, unblockable (POSIX). */
#define MANPROCSIG_USR1  10 /* User-defined MANPROCSIG_nal 1 (POSIX). */
#define MANPROCSIG_SEGV  11 /* Segmentation violation (ANSI). */
#define MANPROCSIG_USR2  12 /* User-defined MANPROCSIG_nal 2 (POSIX). */
#define MANPROCSIG_PIPE  13 /* Broken pipe (POSIX). */
#define MANPROCSIG_ALRM  14 /* Alarm clock (POSIX). */
#define MANPROCSIG_TERM  15 /* Termination (ANSI). */
#define MANPROCSIG_STKFLT 16 /* Stack fault. */
#define MANPROCSIG_CLD  MANPROCSIG_CHLD /* Same as MANPROCSIG_CHLD (System V). */
#define MANPROCSIG_CHLD  17 /* Child status has changed (POSIX). */
#define MANPROCSIG_CONT  18 /* Continue (POSIX). */
#define MANPROCSIG_STOP  19 /* Stop, unblockable (POSIX). */
#define MANPROCSIG_TSTP  20 /* Keyboard stop (POSIX). */
#define MANPROCSIG_TTIN  21 /* Background read from tty (POSIX). */
#define MANPROCSIG_TTOU  22 /* Background write to tty (POSIX). */
#define MANPROCSIG_URG  23 /* Urgent condition on socket (4.2 BSD). */
#define MANPROCSIG_XCPU  24 /* CPU limit exceeded (4.2 BSD). */
#define MANPROCSIG_XFSZ  25 /* File size limit exceeded (4.2 BSD). */
#define MANPROCSIG_VTALRM 26 /* Virtual alarm clock (4.2 BSD). */
#define MANPROCSIG_PROF  27 /* Profiling alarm clock (4.2 BSD). */
#define MANPROCSIG_WINCH 28 /* Window size change (4.3 BSD, Sun). */
#define MANPROCSIG_POLL  MANPROCSIG_IO /* Pollable event occurred (System V). */
#define MANPROCSIG_IO  29 /* I/O now possible (4.2 BSD). */
#define MANPROCSIG_PWR  30 /* Power failure restart (System V). */
#define MANPROCSIG_SYS  31 /* Bad system call. */
#define MANPROCSIG_UNUSED 31

#define T Exception_t
typedef struct Exception_t{
	char *reason;
}Exception_t;

typedef struct Exception_frame{
	struct Exception_frame *prev;
	jmp_buf env;
	const char *file;
	int line;
	const T* exception;
}Exception_frame;

extern Exception_frame *Exception_stack;

enum{
	EXCEPTION_ENTERED=0,
	EXCEPTION_RAISED,
	EXCEPTION_HANDLED,
	EXCEPTION_FINALIZED
};

/* Manage all process signal,and automanage signal by process cause exit directoryly,*/
#define ManProcAllSig \
    int sum = 31; \
   while(sum){ \
    signal(sum,handle_proc_sig); \
    sum--; \
}

/*Throw a exception*/
#define throw(e) exception_raise(&(e),__FILE__,__LINE__)

#define rethrow exception_raise(exception_frame.exception, \
          exception_frame.file,exception_frame.line)

void handle_proc_sig(int signo);

void abort_without_exception(const Exception_t *e,const char *file,int line);

void exception_raise(const T *e,const char *file,int line);

#define try do{ \
    volatile int exception_flag; \
    Exception_frame exception_frame; \
    exception_frame.prev = Exception_stack; \
    Exception_stack = &exception_frame; \
    ManProcAllSig \
    exception_flag = setjmp(exception_frame.env); \
    if (exception_flag == EXCEPTION_ENTERED) \
    {

#define catch(e) \
  if(exception_flag == EXCEPTION_ENTERED) \
   Exception_stack = Exception_stack->prev; \
  }else if(exception_flag == e){ \
   exception_flag = EXCEPTION_HANDLED;

#define try_return \
   switch(Exception_stack = Exception_stack->prev,0) \
    default: return

#define catch_else \
   if(exception_flag == EXCEPTION_ENTERED) \
    Exception_stack = Exception_stack->prev; \
    }else if(exception_flag != EXCEPTION_HANDLED){ \
     exception_flag = EXCEPTION_HANDLED;

#define end_try \
    if(exception_flag == EXCEPTION_ENTERED) \
     Exception_stack = Exception_stack->prev; \
     } \
     if (exception_flag == EXCEPTION_RAISED) \
      exception_raise(exception_frame.exception, \
        exception_frame.file,exception_frame.line); \
    }while(0)

#define finally \
    if(exception_flag == EXCEPTION_ENTERED) \
     Exception_stack = Exception_stack->prev; \
    }{ \
     if(exception_flag == EXCEPTION_ENTERED) \
       exception_flag = EXCEPTION_FINALIZED;

#undef T
#endif /* EXCEPTION_H_ */


exception.c

#include "exception.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>


Exception_frame *Exception_stack = NULL;


void exception_raise(const Exception_t *e,const char *file,int line)
{
	Exception_frame *p = Exception_stack;

	assert(e);

	if(p == NULL)
	{
		abort_without_exception(e,file,line);
	}

	p->exception = e;
	p->file = file;
	p->line = line;
	Exception_stack = Exception_stack->prev;
	longjmp(p->env,EXCEPTION_RAISED);
}


void abort_without_exception(const Exception_t *e,const char *file,int line)
{
	//fprintf(stderr,"Uncaught exception");

	if(e->reason)
	{
		fprintf(stderr," %s",e->reason);
	}
	else
	{
		fprintf(stderr,"at 0x%p",e);
	}
		
	if(file && line > 0)
	{
		fprintf(stderr, "raised at %s:%d\n",file,line);
	}
	fprintf(stderr,"aborting...\n");
	fflush(stderr);
	abort();
}


void handle_proc_sig(int signo)
{
	if( signo == MANPROCSIG_HUP )
		printf(" Hangup (POSIX). \r\n");
	else if( signo == MANPROCSIG_INT )
		printf(" Interrupt (ANSI). \r\n");
	else if( signo == MANPROCSIG_QUIT )
		printf(" Quit (POSIX). \r\n");
	else if( signo == MANPROCSIG_ILL )
		printf(" Illegal instruction (ANSI). \r\n");
	else if( signo == MANPROCSIG_TRAP )
		printf(" Trace trap (POSIX). \r\n");
	else if( signo == MANPROCSIG_ABRT )
		printf(" Abort (ANSI). \r\n");
	else if( signo == MANPROCSIG_IOT )
		printf(" IOT trap (4.2 BSD). \r\n");
	else if( signo == MANPROCSIG_BUS )
		printf(" BUS error (4.2 BSD). \r\n");
	else if( signo == MANPROCSIG_FPE )
		printf(" Floating-point exception (ANSI). \r\n");
	else if( signo == MANPROCSIG_KILL )
		printf(" Kill, unblockable (POSIX). \r\n");
	else if( signo == MANPROCSIG_USR1 )
		printf(" User-defined signal if( signo == (POSIX). \r\n");
	else if( signo == MANPROCSIG_SEGV )
		printf(" Segmentation violation (ANSI). \r\n");
	else if( signo == MANPROCSIG_USR2 )
		printf(" User-defined signal 2 (POSIX). \r\n");
	else if( signo == MANPROCSIG_PIPE )
		printf(" Broken pipe (POSIX). \r\n");
	else if( signo == MANPROCSIG_ALRM )
		printf(" Alarm clock (POSIX). \r\n");
	else if( signo == MANPROCSIG_TERM )
		printf(" Termination (ANSI). \r\n");
	else if( signo == MANPROCSIG_STKFLT )
		printf(" Stack fault. \r\n");
	else if( signo == MANPROCSIG_CLD )
		printf(" Same as SIGCHLD (System V). \r\n");
	else if( signo == MANPROCSIG_CHLD )
		printf(" Child status has changed (POSIX). \r\n");
	else if( signo == MANPROCSIG_CONT )
		printf(" Continue (POSIX). \r\n");
	else if( signo == MANPROCSIG_STOP )
		printf(" Stop, unblockable (POSIX). \r\n");
	else if( signo == MANPROCSIG_TSTP )
		printf(" Keyboard stop (POSIX). \r\n");
	else if( signo == MANPROCSIG_TTIN )
		printf(" Background read from tty (POSIX). \r\n");
	else if( signo == MANPROCSIG_TTOU )
		printf(" Background write to tty (POSIX). \r\n");
	else if( signo == MANPROCSIG_URG )
		printf(" Urgent condition on socket (4.2 BSD). \r\n");
	else if( signo == MANPROCSIG_XCPU )
		printf(" CPU limit exceeded (4.2 BSD). \r\n");
	else if( signo == MANPROCSIG_XFSZ )
		printf(" File size limit exceeded (4.2 BSD). \r\n");
	else if( signo == MANPROCSIG_VTALRM )
		printf(" Virtual alarm clock (4.2 BSD). \r\n");
	else if( signo == MANPROCSIG_PROF )
		printf(" Profiling alarm clock (4.2 BSD). \r\n");
	else if( signo == MANPROCSIG_WINCH )
		printf(" Window size change (4.3 BSD, Sun). \r\n");
	else if( signo == MANPROCSIG_POLL )
		printf(" Pollable event occurred (System V). \r\n");
	else if( signo == MANPROCSIG_IO )
		printf(" I/O now possible (4.2 BSD). \r\n");
	else if( signo == MANPROCSIG_PWR )
		printf(" Power failure restart (System V). \r\n");
	else if( signo == MANPROCSIG_SYS)
		printf(" Bad system call. \r\n");
	else if( signo == MANPROCSIG_UNUSED)
		printf(" Unknow erroe. \r\n");

	Exception_frame *p = Exception_stack;
	Exception_stack = Exception_stack->prev;
	longjmp(p->env,signo);

	// exit(0);
	//exit process
}


测试:test.c

#include <stdio.h>
#include "exception.h"

void test()
{
	char *a=NULL;
	*a=1;
}

int main()
{
	try
	{
		test();			//SimulateNULLpointerexception!!
	}
	catch(MANPROCSIG_SEGV)	//Catchtheexception
	{
		printf("NULLpointer!!\r\n");
	}
	catch_else
	{
		printf("UnknowError!!\r\n");
	}
	finally
	{
		printf("DONE\r\n");
	}
	end_try;

	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值