// names are unique within a function, any valid variable name
// a jump table try, allowing return values to determine the exception thrown(index in a jump table, -1 being success for example)
// you only need to put in what you need, not all exceptions, or total exception count
#define GTRY(name, exc) void* __jt_##name[exc];int __jtix_##name = 0;
// register an exception in the jump table. you don't need to do them all
#define GTEX(name, exception) __jtix_##name;__jt_##name[__jtix_##name++] = &&__tr_##exception##name;
// resets the jump table index to a given value, useful for overwriting exceptions without a new try.
#define GTRST(name, index) __jtix_##name = index;
// a standard try, doesn't actually add anything, but for cleanliness.
#define TRY(name) ;
// throw an exception by name
#define THROW(name, exception) goto __tr_##exception##name;
// throws an exception by jump table index
#define GTHROW(name, exn) goto *__jt_##name[exn];
// begins a catch block
#define CATCH(name, exception) goto __trend_##name;__tr_##exception##name:;
// signifies where the try ends
#define ENDTRY(name) __trend_##name:;
// 'finally' blocks need only be put after an end try.
Usage Example:
int main(int argc, char* argv[]) {
TRY(magic)
THROW(magic, EOF)
CATCH(magic, EOF)
printf("eof!\n");
ENDTRY(magic)
printf("complete\n");
GTRY(fagic, 2)
int eof = GTEX(fagic, EOF)
int rst = GTEX(fagic, RST)
GTHROW(fagic, rst)
CATCH(fagic, EOF)
printf("eof2!\n");
CATCH(fagic, RST)
printf("rst\n");
ENDTRY(fagic);
//
TRY(nest) {
THROW(nest, EOF);
} CATCH(nest, EOF) {
printf("eof3!\n");
}
ENDTRY(nest)
printf("complete3\n");
return 0;
}
My purpose was to create a macro-based exception system that can run on embedded devices with ease(magic is done compile-time). There is a potential performance malice if CPUs don't support labels as values and GTRY is used.
-
1\$\begingroup\$ Could you provide some code that really uses this, the example you give will not compile, since there is no function wrapping it? \$\endgroup\$pacmaninbw– pacmaninbw ♦2016年07月06日 15:33:11 +00:00Commented Jul 6, 2016 at 15:33
1 Answer 1
Semantics
In the languages that implement try
, throw
and catch
the scope is generally larger than a single function. The scope of the exception handling is set by the try
block and the catch
block. The C goto
is limited to the current function, to jump outside of the current function you need to use setjmp()
and longjmp()
. Your implementation does not seem to use setjmp()
and longjmp()
.
Maintainability
Using a goto
is generally decreasing maintainability, hiding a goto
is a bad idea. If I have to maintain code that contains a goto I want to be able to immediately know that there is a goto and I want to be able to find the label immediately as well.
Performance
A reason to use goto
is to improve performance. When goto's actually degrade performance that is another reason not to use them.