Question

I just started reading this article about exception handling in c with the use of setjmp( jmp_buf ) and longjmp( jmp_buf, int ). So I basically build the linked list that uses the local variables from type xRecord and links it to the list. (Example 2) It works just fine. But in example 3 the steps get summarized into macros (XTRY and XEND). What irritates me most is that the actual switch statement of example 2 just "vanished" in 3.

Example 2:

   #define DIVIDE_BY_ZERO -3
   int SomeFunction(int a, int b)
   {
      if (b == 0) // can't divide by 0
         XRaise(DIVIDE_BY_ZERO);
      return a / b;
   }

   void main(void)
   {
      XRecord XData;
      XLinkExceptionRecord(&XData);
      switch (setjmp(XData.Context))
      {
         case 0: // this is the code block
            {
               int Result = SomeFunction(7, 0);
               // continue working with Result
            }
            break;
         case DIVIDE_BY_ZERO:
            printf("a division by zero occurred\n");
            break;
         default:
            printf("some other error occurred\n");
            break;
         case XFINALLY:
            printf("cleaning up\n");
      }
      XUnLinkExceptionRecord(&XData);
   }

Example 3:

void main(void)
   {
      XTRY
         case XCODE: // this is the code block
            {
               int Result = SomeFunction(7, 0);
               // continue working with Result
            }
            break;
         case DIVIDE_BY_ZERO: // handler for a
                                 specific exception
            printf("a division by zero occurred\n");
            break;
         default: // default handler
            printf("some other error occurred\n");
            break;
         case XFINALLY: // finally handler
            printf("cleaning up\n");
      XEND
   }

My question is, how can I build these "opening and closing" macros?

Was it helpful?

Solution

If you compare the two examples, and keep in mind that C macros are simple text substitutions, what the macros should be is evident:

#define XTRY  XRecord XData; \
              XLinkExceptionRecord(&XData); \
              switch (setjmp(XData.Context)) \
              {

#define XEND  } \
              XUnLinkExceptionRecord(&XData);

Note the use of \ to allow the macro to span more than one line.

You may also want to have the macros open and close a new scope (by adding { and }), so that using the macros multiple in succession doesn't give an error due to multiple definitions of the variable XData. You can also use the do / while(0) trick to allow these macros to be placed directly inside if, for, etc. without issues.

OTHER TIPS

Don't hide the {} this only causes trouble. With a C99 compliant compiler, you can hide local variables and some code that is executed before and after the block:

#define MY_BLOCK                                          \
for (int once = 0; once < 1; ++once)                      \
  for (XRecord XData = { 0 }; once < 1; ++once)           \
    for (XLinkExceptionRecord(&XData); (XUnLinkExceptionRecord(&XData), (once < 1)); ++once) \
       switch (setjmp(XData.Context))

Benefit would be that you only need one macro instead of two, and the {} would clearly indicate the scope of the construct, even for your favorite editor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top