Ben yazdım istisna Java benzeri taşıma mekanizmasını kullanarak C setjmp(), longjmp()ve sistem fonksiyonlarını. Özel istisnaları yakalar ama aynı zamanda SIGSEGV. Fonksiyon çağrılarında çalışan ve en yaygın iki iş parçacığı uygulamasını destekleyen istisna işleme bloklarının sonsuz yuvalanmasına sahiptir. Bağlantı zamanı devralma özelliğine sahip istisna sınıflarından oluşan bir ağaç hiyerarşisi tanımlamanıza olanak tanır ve catchifade, yakalanması veya aktarılması gerekip gerekmediğini görmek için bu ağacı yürütür.
İşte bunu kullanarak kodun nasıl göründüğüne dair bir örnek:
try
{
*((int *)0) = 0;
}
catch (SegmentationFault, e)
{
long f[] = { 'i', 'l', 'l', 'e', 'g', 'a', 'l' };
((void(*)())f)();
}
finally
{
return(1 / strcmp("", ""));
}
Ve burada içerme dosyasının çok fazla mantık içeren bir kısmı:
#ifndef _EXCEPT_H
#define _EXCEPT_H
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include "Lifo.h"
#include "List.h"
#define SETJMP(env) sigsetjmp(env, 1)
#define LONGJMP(env, val) siglongjmp(env, val)
#define JMP_BUF sigjmp_buf
typedef void (* Handler)(int);
typedef struct _Class *ClassRef;
struct _Class
{
int notRethrown;
ClassRef parent;
char * name;
int signalNumber;
};
typedef struct _Class Class[1];
typedef enum _Scope /* exception handling scope */
{
OUTSIDE = -1,
INTERNAL,
TRY,
CATCH,
FINALLY
} Scope;
typedef enum _State /* exception handling state */
{
EMPTY,
PENDING,
CAUGHT
} State;
typedef struct _Except /* exception handle */
{
int notRethrown;
State state;
JMP_BUF throwBuf;
JMP_BUF finalBuf;
ClassRef class;
void * pData;
char * file;
int line;
int ready;
Scope scope;
int first;
List * checkList;
char* tryFile;
int tryLine;
ClassRef (*getClass)(void);
char * (*getMessage)(void);
void * (*getData)(void);
void (*printTryTrace)(FILE*);
} Except;
typedef struct _Context /* exception context per thread */
{
Except * pEx;
Lifo * exStack;
char message[1024];
Handler sigAbrtHandler;
Handler sigFpeHandler;
Handler sigIllHandler;
Handler sigSegvHandler;
Handler sigBusHandler;
} Context;
extern Context * pC;
extern Class Throwable;
#define except_class_declare(child, parent) extern Class child
#define except_class_define(child, parent) Class child = { 1, parent, #child }
except_class_declare(Exception, Throwable);
except_class_declare(OutOfMemoryError, Exception);
except_class_declare(FailedAssertion, Exception);
except_class_declare(RuntimeException, Exception);
except_class_declare(AbnormalTermination, RuntimeException);
except_class_declare(ArithmeticException, RuntimeException);
except_class_declare(IllegalInstruction, RuntimeException);
except_class_declare(SegmentationFault, RuntimeException);
except_class_declare(BusError, RuntimeException);
#ifdef DEBUG
#define CHECKED \
static int checked
#define CHECK_BEGIN(pC, pChecked, file, line) \
ExceptCheckBegin(pC, pChecked, file, line)
#define CHECK(pC, pChecked, class, file, line) \
ExceptCheck(pC, pChecked, class, file, line)
#define CHECK_END \
!checked
#else
#define CHECKED
#define CHECK_BEGIN(pC, pChecked, file, line) 1
#define CHECK(pC, pChecked, class, file, line) 1
#define CHECK_END 0
#endif
#define except_thread_cleanup(id) ExceptThreadCleanup(id)
#define try \
ExceptTry(pC, __FILE__, __LINE__); \
while (1) \
{ \
Context * pTmpC = ExceptGetContext(pC); \
Context * pC = pTmpC; \
CHECKED; \
\
if (CHECK_BEGIN(pC, &checked, __FILE__, __LINE__) && \
pC->pEx->ready && SETJMP(pC->pEx->throwBuf) == 0) \
{ \
pC->pEx->scope = TRY; \
do \
{
#define catch(class, e) \
} \
while (0); \
} \
else if (CHECK(pC, &checked, class, __FILE__, __LINE__) && \
pC->pEx->ready && ExceptCatch(pC, class)) \
{ \
Except *e = LifoPeek(pC->exStack, 1); \
pC->pEx->scope = CATCH; \
do \
{
#define finally \
} \
while (0); \
} \
if (CHECK_END) \
continue; \
if (!pC->pEx->ready && SETJMP(pC->pEx->finalBuf) == 0) \
pC->pEx->ready = 1; \
else \
break; \
} \
ExceptGetContext(pC)->pEx->scope = FINALLY; \
while (ExceptGetContext(pC)->pEx->ready > 0 || ExceptFinally(pC)) \
while (ExceptGetContext(pC)->pEx->ready-- > 0)
#define throw(pExceptOrClass, pData) \
ExceptThrow(pC, (ClassRef)pExceptOrClass, pData, __FILE__, __LINE__)
#define return(x) \
{ \
if (ExceptGetScope(pC) != OUTSIDE) \
{ \
void * pData = malloc(sizeof(JMP_BUF)); \
ExceptGetContext(pC)->pEx->pData = pData; \
if (SETJMP(*(JMP_BUF *)pData) == 0) \
ExceptReturn(pC); \
else \
free(pData); \
} \
return x; \
}
#define pending \
(ExceptGetContext(pC)->pEx->state == PENDING)
extern Scope ExceptGetScope(Context *pC);
extern Context *ExceptGetContext(Context *pC);
extern void ExceptThreadCleanup(int threadId);
extern void ExceptTry(Context *pC, char *file, int line);
extern void ExceptThrow(Context *pC, void * pExceptOrClass,
void *pData, char *file, int line);
extern int ExceptCatch(Context *pC, ClassRef class);
extern int ExceptFinally(Context *pC);
extern void ExceptReturn(Context *pC);
extern int ExceptCheckBegin(Context *pC, int *pChecked,
char *file, int line);
extern int ExceptCheck(Context *pC, int *pChecked, ClassRef class,
char *file, int line);
#endif
Ayrıca sinyal işleme ve bazı defter tutma mantığını içeren bir C modülü de var.
Uygulamak son derece zordu size söyleyebilirim ve neredeyse bırakıyordum. Java'yı olabildiğince yakın hale getirmek için gerçekten çabaladım; Sadece C ile ne kadar ileri gittiğimi şaşırtıcı buldum.
Eğer ilgilenirsen bana seslen.