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>
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 <signal.h>
#include <stdlib.h>
#include "exception.h"
#include <unistd.h>

void test1(){
	char* a = NULL;
	*a = 1;
}
void test2(){
	int num = 1;
	while(1){
		printf("number=%d\r\n",num++);
		sleep(1);
	}
}
int main(){

	try{

      test2();//Simulate NULL pointer exception!!
	}catch(MANPROCSIG_SEGV){ //Catch the exception
		printf("NULL pointer !!\r\n");
	}catch_else{
		printf("Unknow Error!!\r\n");
	}finally{
		printf("DONE \r\n");
	}end_try;
	return 0;

}



  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值