HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

C try/catch macros

Submitted by: @import:stackexchange-codereview··
0
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?

#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 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 utlErr etc and separate words in utl_jbn etc



  • utl_TRYMAX might be expected to be UTL_TRYMAX and if that limit is exceeded, utlTry seems 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.