Created
June 10, 2019 14:35
-
-
Save iafisher/7b1b7c3b69a5ecccfffba199360cc7d1 to your computer and use it in GitHub Desktop.
Exception handling with try, catch and throw statements, implemented in pure C99
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <setjmp.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
const char* e = NULL; | |
#define EXCEPTION_DEPTH 128 | |
jmp_buf* iafisher_trycatch_stack[EXCEPTION_DEPTH]; | |
size_t iafisher_trycatch_stack_len = 0; | |
void iafisher_trycatch_push(jmp_buf* jbuf) { | |
if (iafisher_trycatch_stack_len == EXCEPTION_DEPTH) { | |
fprintf(stderr, "Error in iafisher/trycatch: exceeded max exceptions\n"); | |
exit(EXIT_FAILURE); | |
} | |
iafisher_trycatch_stack[iafisher_trycatch_stack_len++] = jbuf; | |
} | |
jmp_buf* iafisher_trycatch_pop(void) { | |
if (!iafisher_trycatch_stack_len) { | |
fprintf(stderr, "Uncaught exception from iafisher/trycatch library: %s\n", e); | |
exit(EXIT_FAILURE); | |
} | |
return iafisher_trycatch_stack[--iafisher_trycatch_stack_len]; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A toy library for throwing and catching exceptions in C with a Python-like | |
* syntax. | |
* | |
* | |
* EXAMPLE | |
********** | |
* | |
* #include <stdio.h> | |
* #include "trycatch.h" | |
* | |
* int bar() { | |
* throw ("bar could not compute"); | |
* return 41; | |
* } | |
* | |
* int foo() { | |
* try { | |
* return bar() + 1; | |
* } catch { | |
* printf("foo caught error: %s\n", e); | |
* throw ("foo could not compute"); | |
* } | |
* } * | |
* int main() { | |
* try { | |
* int x = foo(); | |
* printf("Result: %d\n", x); | |
* } catch { | |
* printf("main caught error: %s\n", e); | |
* } | |
* } | |
* | |
* | |
* DOCUMENTATION | |
**************** | |
* | |
* You can use this library by including "trycatch.h" and adding "trycatch.c" | |
* to your build system, although this is a toy library which I don't recommend | |
* using in production. | |
* | |
* When you want to throw an exception, use the `throw` macro: | |
* | |
* throw ("something went wrong"); | |
* | |
* The argument to `throw` is a string that is made available to the `catch` | |
* clause that catches the exception. | |
* | |
* To catch an exception, use the `try` and `catch` macros: | |
* | |
* try { | |
* subroutine_that_may_fail(); | |
* } catch { | |
* printf("Error: %s\n", e); | |
* } | |
* | |
* If any function in the `try` clause throws an exception, then the `catch` | |
* clause is executed. Otherwise, the `catch` clause is not executed and | |
* the program continues normally. | |
* | |
* In the `catch` clause, a string variable `e` is available which holds the | |
* message passed to the `throw` exception. | |
* | |
* The function that throws does not have to be directly called by the | |
* function with the try-catch statement, i.e. if `f`, which has a try-catch | |
* statement, calls `g`, which in turns calls a function `h` which throws an | |
* exception, then `f` will catch the exception, skipping over `g`. | |
* | |
* Technical limitations: | |
* - You cannot catch an exception thrown in a different thread. | |
* - You cannot exceed a certain fixed number of active try blocks at any | |
* one time. | |
* | |
* Author: Ian Fisher ([email protected]) | |
* Version: June 2019 | |
*/ | |
#ifndef IAFISHER_TRYCATCH_H | |
#define IAFISHER_TRYCATCH_H | |
#include <setjmp.h> | |
#define try \ | |
jmp_buf jmp_buffer_name; \ | |
iafisher_trycatch_push(&jmp_buffer_name); \ | |
int setjmp_result_name = setjmp(jmp_buffer_name); \ | |
if (setjmp_result_name == 0) \ | |
#define catch else | |
#define throw(x) \ | |
do { e = x; longjmp(*iafisher_trycatch_pop(), 0); } while (0) | |
extern const char* e; | |
/* These functions, macros and variables are for internal use only. */ | |
#define tokenpaste(x, y) x ## y | |
#define tokenpaste2(x, y) tokenpaste(x, y) | |
#define jmp_buffer_name \ | |
tokenpaste2(iafisher_trycatch_jmp_buffer, __LINE__) | |
#define setjmp_result_name \ | |
tokenpaste2(iafisher_trycatch_setjmp_result, __LINE__) | |
extern void iafisher_trycatch_push(jmp_buf*); | |
extern jmp_buf* iafisher_trycatch_pop(void); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment