为了在C语言环境中抓住异常。。。

来源:互联网 发布:wamp mysql 无法启动 编辑:程序博客网 时间:2024/05/18 03:36
c 写的程序经常会有空指针引用,遇到这种情况,程序会被系统强行终止,客户会看到一个该死的对话框,里面写着神秘的诅咒代码。
为了不被使用程序的用户咒骂,应该温和的给予温柔的提示,并保存当前的工作内容,
于是我开发了这个小工具代码,允许你像 Java 一样的抓住异常,这是程序例子:
支持多线程,支持嵌套 try

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

int main()
{
    try {

        try {
             int *a = NULL;
             *a = 1;
        } catch(b) {
            printf("some error 2. %x\n", b);
        } finally {
        }

        int *a = NULL;
        *a = 1;

    } catch(a) {
        printf("some error 1. %x\n", a);
    } finally

    printf("over\n");
    return 0;
} 

最新的代码版本
https://github.com/yanmingsohu/c-tool

头文件:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
// J.yanming 2013/7/19 yanming-sohu@sohu.com
// CatfoOD crazy code.
// 如果不需要导出 try 等关键字,则定义 NOT_EXPORT_TRY
// finally 必须出现在 catch 之后!

#ifndef _EXCEPTION_J_
#define _EXCEPTION_J_

#include <setjmp.h>

#define _MAX_EXCEPTION_DEEP_ 255
#define _MAX_THREAD_COUNT_ 255
#define _HAS_EXCEPTION_ 1
#define _NOT_EXCEPTION_ 0

#ifdef __WIN32__
#include <Windows.h>
#define THREAD_ID DWORD
#define GET_CURRENT_THREAD GetCurrentThreadId
typedef EXCEPTION_POINTERS* EXCEPTION_INF;
#else
#ifdef __linux__
#include <pthread.h>
#define THREAD_ID pthread_t
#define GET_CURRENT_THREAD pthread_self
typedef void* EXCEPTION_INF; // ?
#else
// Other system.
#define THREAD_ID int
#define GET_CURRENT_THREAD i_dont_know
typedef void* EXCEPTION_INF;
#endif // __linux__
#endif // __WIN32__


typedef struct __THREAD_MARK {
    EXCEPTION_INF exception_info;
    THREAD_ID thread_id;
    int current_exp_mark;
    jmp_buf mark[_MAX_EXCEPTION_DEEP_];
} THREAD_MARK;


typedef jmp_buf* ExceptionMark;

void _init_exception();
void _exit_exception_deep();
THREAD_MARK* _create_exception_deep();


#define _TRY_ \
_init_exception(); \
THREAD_MARK* ___exp_mark = _create_exception_deep(); \
if (___exp_mark && \
(setjmp(___exp_mark->mark[___exp_mark->current_exp_mark]) == _NOT_EXCEPTION_) ) {

#define _CATCH_(x) \
_exit_exception_deep(___exp_mark); \
} else { \
_exit_exception_deep(___exp_mark); \
EXCEPTION_INF x = ___exp_mark->exception_info;

#define _TEND_ \
}


#ifndef NOT_EXPORT_TRY
    #define try _TRY_
    #define catch _CATCH_
    #define finally _TEND_
#endif

#endif

源文件:

 

// J.yanming 2013/7/19 yanming-sohu@sohu.com
// CatfoOD crazy code.

#include "exception.h"


static THREAD_MARK thread_mark[_MAX_THREAD_COUNT_];
static int mark_length = 0;
static int inited = 0;


static void reclaimMemory() {
    // 需要同步锁,防止在读取的时候修改了内存顺序
}

static THREAD_MARK* findThread() {
    THREAD_ID tid = GET_CURRENT_THREAD();
    THREAD_MARK* tm = NULL;
    int i;

    for (i=0; i<mark_length; ++i) {
        if (thread_mark[i].thread_id == tid) {
            tm = thread_mark + i;
            break;
        }
    }
    return tm;
}

static THREAD_MARK* newThread() {
    if (mark_length >= _MAX_THREAD_COUNT_) {
        reclaimMemory();
        if (mark_length >= _MAX_THREAD_COUNT_) {
            return NULL;
        }
    }

    THREAD_ID tid = GET_CURRENT_THREAD();
    THREAD_MARK* tm = &thread_mark[mark_length++];
    tm->thread_id = tid;

    return tm;
}

static void outThread(THREAD_MARK* tm) {
    if (tm) {
        tm->thread_id = 0;
    }
}

#ifdef __WIN32__
static long WINAPI _ExceptionGlobeFilter(EXCEPTION_POINTERS* lParam) {
    THREAD_MARK* tm = findThread();
    if (tm->current_exp_mark) {
        tm->exception_info = lParam;
        longjmp(tm->mark[tm->current_exp_mark], _HAS_EXCEPTION_);
    }
    return 1;
}
#endif

void _init_exception() {
    if (!inited) {
#ifdef __WIN32__
        SetUnhandledExceptionFilter(_ExceptionGlobeFilter);
#endif
        inited = 1;
    }
}

THREAD_MARK* _create_exception_deep() {
    THREAD_MARK* tm = findThread();
    if (!tm) tm = newThread();
    if (!tm) return NULL;

    int deep = tm->current_exp_mark;
    if (deep >= _MAX_EXCEPTION_DEEP_) {
        return NULL;
    } else {
        tm->current_exp_mark++;
    }
    return tm;
}

void _exit_exception_deep(THREAD_MARK* tm) {
    if (tm->current_exp_mark > 0) {
        --tm->current_exp_mark;
    } else {
        outThread(tm);
    }
}