Exception Handling in C Without C++
by Tom Schotland and Peter Petersen


Example 1:

jmp_buf jumper;
int SomeFunction(int a, int b)
{
  if (b == 0) // can't divide by 0
    longjmp(jumper, -3);
  return a / b;
}
void main(void)
{
  if (setjmp(jumper) == 0)
  {
    int Result = SomeFunction(7, 0);
    // continue working with Result
  }
  else
    printf("an error occured\n");
}


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
}

Example 4:
  XTRY
    case XCODE
      // code body
      break;
    [case ERROR_1:
      // handler for ERROR_1
      break;
      // more handlers go here
     ...]
    default:
      // handle all other errors
      break;
    case XFINALLY:
      // finally handler
  XEND or XENDX

Example 5:
void main(void)
{
   jmp_buf jumper;
   int LocalVar = 1;
   printf("1: %i\n", LocalVar);
   if (setjmp(jumper) == 0)
   {
      LocalVar++;
      printf("2: %i\n", LocalVar);
      longjmp(jumper, 1);
   }
   LocalVar++;
   printf("3: %i\n", LocalVar);
}


Table 1:
Program        Code Size  Time (no throws)   Time (with throws)

XBench.c       4.6k        1392ms             1362ms
CPPBench.cpp  35.3k        1492ms            71343ms            



Listing One
; RTFEX32.ASM
; Copyright (c) 1998,99 On Time
; http://www.on-time.com
; Custom context save/restore functions for C Exception Handling Library 
; This is what we want to implement:
;   typedef struct {
;      unsigned long esi, edi, ebx, ret, ebp, esp;
;   } XContext;
;   int  __stdcall XSaveContext(XContext * C);
;   void __stdcall XRestoreContext(XContext * C, int Value); 

 .386

XContext STRUC
  _esi DD ?
  _edi DD ?
  _ebx DD ?
  _ret DD ?
  _ebp DD ?
  _esp DD ?
XContext ENDS

_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'

ASSUME CS:_TEXT

PUBLIC XSaveContext
PUBLIC _XSaveContext@4
PUBLIC XRestoreContext
PUBLIC _XRestoreContext@8

XSaveContext proc near
_XSaveContext@4 label near
   pop ecx                 ; ret address
   pop edx                 ; parameter C
   mov [edx+_esi], esi     ; save all required registers
   mov [edx+_edi], edi
   mov [edx+_ebx], ebx
   mov [edx+_ret], ecx
   mov [edx+_ebp], ebp
   mov [edx+_esp], esp
   xor eax, eax            ; return code is zero
   jmp ecx                 ; and return
XSaveContext endp

XRestoreContext proc near
_XRestoreContext@8 label near
   mov edx, [esp+4]        ; parameter C
   mov eax, [esp+8]        ; parameter Value, set as return value
   mov esi, [edx+_esi]     ; restore all required registers
   mov edi, [edx+_edi]
   mov ebx, [edx+_ebx]
   mov ebp, [edx+_ebp]
   mov esp, [edx+_esp]
   jmp [edx+_ret]          ; and jump to saved context
XRestoreContext endp

_TEXT ENDS

END


Listing Two
// XBENCH.C
// Copyright (c) 1998,99 On Time
// http://www.on-time.com
// Benchmark for the C Exception Handling Library

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

#include <rtfex.h>

#define DIVIDE_BY_ZERO -3 // an error code

// some global variables to count iterations, exceptions, and cleanups
int Calls, Exceptions, Finallys;

///////////////////////////////////////
int SomeFunction(int a, int b)
// functiom which can raise an exception
{
   if (b == 0)
      XRaise(DIVIDE_BY_ZERO);
   return a / b;
}
///////////////////////////////////////
int TestFunction(int a, int b)
// test function containing an XTRY block
{
   int volatile Result;
   Calls++;
   XTRY
      case XCODE:
         Result = SomeFunction(a, b);
         break;
      case DIVIDE_BY_ZERO:
         Exceptions++;
         XHandled();
         break;
      default:
         printf("unknown exception!\n");
         break;
      case XFINALLY:
         Finallys++;
         break;
   XENDX
   return Result;
}
///////////////////////////////////////
void Bench(int a, int b, int Iterations)
// benchmark function to call TestFunction in a loop
// and print timing and statistics 
{
   DWORD T0, T1;
   int i;
   Calls = Exceptions = Finallys = 0;
   T0 = GetTickCount();
   for (i=0; i<Iterations; i++)
      TestFunction(a, b);
   T1 = GetTickCount();
   printf("%10i  %10i  %10i    %10u\n", Calls, Exceptions, Finallys, T1-T0);
}
///////////////////////////////////////
int main(void)
{
   printf("Interation  Exceptions    Finallys  Milliseconds\n"
          "------------------------------------------------\n");
   Bench(1, 1, 1000000);   // no exceptions
   Bench(1, 0, 1000000);   // raise one exception per loop
   return 0;
}


Listing Three
// CPPBENCH.CPP
// Copyright (c) 1998,99 On Time
// http://www.on-time.com
// Benchmark for C++ Exception Handling

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

#define DIVIDE_BY_ZERO -3 // an error code

// some global variables to count iterations, exceptions, and cleanups

int Calls, Exceptions, Finallys;

///////////////////////////////////////
int SomeFunction(int a, int b)
// functiom which can raise an exception
{
   if (b == 0)
      throw DIVIDE_BY_ZERO;
   return a / b;
}
///////////////////////////////////////
int TestFunction(int a, int b)
// test function containing try block
{
   int Result;
   class Finally {
   public:
      Finally()  { Calls++; }
      ~Finally() { Finallys++; }
   } FinallyHandler;

   try
   {
      Result = SomeFunction(a, b);
   }
   catch (int& ErrorCode)
   {
      switch (ErrorCode)
      {
         case DIVIDE_BY_ZERO:
            Exceptions++;
            break;
         default:
            printf("unknown exception!\n");
            throw;
       }
   }
   catch (...)
   {
      printf("non integer exception!\n");
      throw;
   }
   return Result;
}
///////////////////////////////////////
void Bench(int a, int b, int Iterations)
// benchmark function to call TestFunction in a loop
// and print timing and statistics 
{
   DWORD T0, T1;
   int i;

   Calls = Exceptions = Finallys = 0;
   T0 = GetTickCount();
   for (i=0; i<Iterations; i++)
      TestFunction(a, b);
   T1 = GetTickCount();
   printf("%10i  %10i  %10i    %10u\n", Calls, Exceptions, Finallys, T1-T0);
}
///////////////////////////////////////
int main(void)
{
   printf("Interation  Exceptions    Finallys  Milliseconds\n"
          "------------------------------------------------\n");
   Bench(1, 1, 1000000);   // no exceptions
   Bench(1, 0, 1000000);   // raise one exception per loop
   return 0;
}







6


