patterncMinor
C try/catch macros
Viewed 0 times
macroscatchtry
Problem
I've created simple try/catch macros that now I'd like to promote to wider use in my projects.
I would have really liked to be able to do without global variables but I have not found any way to do it.
Any suggestion for improvement? Any issue that I may have overlooked?
The macros are to be used in this way:
if there's no handler for an exception, the program exits.
A simple example:
Here is another version I wrote to avoid the p
I would have really liked to be able to do without global variables but I have not found any way to do it.
Any suggestion for improvement? Any issue that I may have overlooked?
#include
#include
#define utl_trymax 16
#ifdef UTL_MAIN
int utlErr = 0;
int utl_jbn = 0;
jmp_buf utl_jbv[utl_trymax];
#else
extern int utlErr;
extern int utl_jbn;
extern jmp_buf utl_jbv[utl_trymax];
#endif
#define utlTry for ( utlErr = -1 \
; utlErr == -1 && utl_jbn 0 ? utl_jbn-- : 0 ) , \
((utlErr > 0)? utlThrow(utlErr) : 0), \
(utlErr = 0) ) \
if ((utlErr = setjmp(utl_jbv[utl_jbn++])) == 0 )
#define utlCatch(e) else if ((utlErr == (e)) && ((utlErr = 0) == 0))
#define utlCatchAny else for ( ;utlErr > 0; utlErr = 0)
#define utlThrow(e) (utlErr=e, (utl_jbn > 0 && utlErr? \
longjmp(utl_jbv[utl_jbn-1], utlErr):\
exit(utlErr)))The macros are to be used in this way:
utlTry {
// Exceptions can be thrown here or in
// any function called from here.
... utlThrow(EX_OUT_OF_MEM);
}
utlCatch(EX_OUT_OF_MEM) {
...
}
utlCatch(EX_DB_UNAVAILABLE) {
...
}
utlCatchAny {
... //optionally catch all other exceptions
}if there's no handler for an exception, the program exits.
A simple example:
#include
#define UTL_MAIN
#include "utltry.h"
void functhrow(int e) { utlThrow(e); }
int main(int argc, char *argv[])
{
int k = 0;
utlTry { functhrow(2); }
utlCatch(1) { k = 1; }
utlCatch(2) { k = 2; }
printf("Caught: %d%s\n",k,(k==2)?" (as expected)":"");
}Here is another version I wrote to avoid the p
Solution
One problem with this is resource leaks. It is not that your macros leak, but that when you use them, you'll leak. For example, suppose you call your
Another problem is that the code doesn't look or behave like normal code. It looks as if I can add a statement between the try and the catch lines, but clearly I cannot. And there is no indication that the catch blocks are conditional. Perhaps this is nitpicking - if it is just you using the macros, I guess you'll get along fine.
Talking of nitpicking, there are some small issues:
Overall, I'd say, don't do it. Error handling the long way can be a pain, but taking shortcuts like this is likely to be worse in the long run (especially if you share your code).
utlTry in function a() that then calls function b() that allocates a resource (opens a file for example) and then calls function c() that does something with the resource. If c() fails and throws, the longjmp back to a() bypasses b() where the resource could be freed. There's no way round this problem and just 'being careful' is unlikely to be enough.Another problem is that the code doesn't look or behave like normal code. It looks as if I can add a statement between the try and the catch lines, but clearly I cannot. And there is no indication that the catch blocks are conditional. Perhaps this is nitpicking - if it is just you using the macros, I guess you'll get along fine.
Talking of nitpicking, there are some small issues:
- you mix naming styles, with camel-case
utlErretc and separate words inutl_jbnetc
utl_TRYMAXmight be expected to beUTL_TRYMAXand if that limit is exceeded,utlTryseems to skip its contained block.
Overall, I'd say, don't do it. Error handling the long way can be a pain, but taking shortcuts like this is likely to be worse in the long run (especially if you share your code).
Context
StackExchange Code Review Q#25124, answer score: 4
Revisions (0)
No revisions yet.