您可以在本书中找到使用 longjmp 的可能实现:C 接口和实现:创建可重用软件的技术 - David Hanson
您可以在此处和此处找到代码,作为书中使用的样式的示例:
除了.h
/* $Id$ */
#ifndef EXCEPT_INCLUDED
#define EXCEPT_INCLUDED
#include <setjmp.h>
#define T Except_T
typedef struct T {
const char *reason;
} T;
typedef struct Except_Frame Except_Frame;
struct Except_Frame {
Except_Frame *prev;
jmp_buf env;
const char *file;
int line;
const T *exception;
};
enum { Except_entered=0, Except_raised,
Except_handled, Except_finalized };
extern Except_Frame *Except_stack;
extern const Except_T Assert_Failed;
void Except_raise(const T *e, const char *file,int line);
#ifdef WIN32
#include <windows.h>
extern int Except_index;
extern void Except_init(void);
extern void Except_push(Except_Frame *fp);
extern void Except_pop(void);
#endif
#ifdef WIN32
/* $Id$ */
#define RAISE(e) Except_raise(&(e), __FILE__, __LINE__)
#define RERAISE Except_raise(Except_frame.exception, \
Except_frame.file, Except_frame.line)
#define RETURN switch (Except_pop(),0) default: return
#define TRY do { \
volatile int Except_flag; \
Except_Frame Except_frame; \
if (Except_index == -1) \
Except_init(); \
Except_push(&Except_frame); \
Except_flag = setjmp(Except_frame.env); \
if (Except_flag == Except_entered) {
#define EXCEPT(e) \
if (Except_flag == Except_entered) Except_pop(); \
} else if (Except_frame.exception == &(e)) { \
Except_flag = Except_handled;
#define ELSE \
if (Except_flag == Except_entered) Except_pop(); \
} else { \
Except_flag = Except_handled;
#define FINALLY \
if (Except_flag == Except_entered) Except_pop(); \
} { \
if (Except_flag == Except_entered) \
Except_flag = Except_finalized;
#define END_TRY \
if (Except_flag == Except_entered) Except_pop(); \
} if (Except_flag == Except_raised) RERAISE; \
} while (0)
#else
#define RAISE(e) Except_raise(&(e), __FILE__, __LINE__)
#define RERAISE Except_raise(Except_frame.exception, \
Except_frame.file, Except_frame.line)
#define RETURN switch (Except_stack = Except_stack->prev,0) default: return
#define TRY do { \
volatile int Except_flag; \
Except_Frame Except_frame; \
Except_frame.prev = Except_stack; \
Except_stack = &Except_frame; \
Except_flag = setjmp(Except_frame.env); \
if (Except_flag == Except_entered) {
#define EXCEPT(e) \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} else if (Except_frame.exception == &(e)) { \
Except_flag = Except_handled;
#define ELSE \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} else { \
Except_flag = Except_handled;
#define FINALLY \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} { \
if (Except_flag == Except_entered) \
Except_flag = Except_finalized;
#define END_TRY \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} if (Except_flag == Except_raised) RERAISE; \
} while (0)
#endif
#undef T
#endif
除了.c
static char rcsid[] = "$Id$" "\n$Id$";
#include <stdlib.h>
#include <stdio.h>
#include "assert.h"
#include "except.h"
#define T Except_T
Except_Frame *Except_stack = NULL;
void Except_raise(const T *e, const char *file,
int line) {
#ifdef WIN32
Except_Frame *p;
if (Except_index == -1)
Except_init();
p = TlsGetValue(Except_index);
#else
Except_Frame *p = Except_stack;
#endif
assert(e);
if (p == NULL) {
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();
}
p->exception = e;
p->file = file;
p->line = line;
#ifdef WIN32
Except_pop();
#else
Except_stack = Except_stack->prev;
#endif
longjmp(p->env, Except_raised);
}
#ifdef WIN32
_CRTIMP void __cdecl _assert(void *, void *, unsigned);
#undef assert
#define assert(e) ((e) || (_assert(#e, __FILE__, __LINE__), 0))
int Except_index = -1;
void Except_init(void) {
BOOL cond;
Except_index = TlsAlloc();
assert(Except_index != TLS_OUT_OF_INDEXES);
cond = TlsSetValue(Except_index, NULL);
assert(cond == TRUE);
}
void Except_push(Except_Frame *fp) {
BOOL cond;
fp->prev = TlsGetValue(Except_index);
cond = TlsSetValue(Except_index, fp);
assert(cond == TRUE);
}
void Except_pop(void) {
BOOL cond;
Except_Frame *tos = TlsGetValue(Except_index);
cond = TlsSetValue(Except_index, tos->prev);
assert(cond == TRUE);
}
#endif