I often will use the following:
#define ERRIF(cond,target) if (cond) goto target
#define ERRHANDLER(target) target:
and you would use it like so:
while (looper) {
do stuff;
ERRIF(readData,ERROR_DATAREAD);
do more stuff;
}
return SUCCESS;
ERRHANDLER(ERROR_DATAREAD)
closeFile();
do some other cleanup
return RC_DATAREAD;
An interesting way to use it is as follows:
ERRIF(openFile(),ERROR_OPENFILE);
ERRIF(allocMem(),ERROR_ALLOCMEM);
ERRIF(readFile(),ERROR_READ);
closeFile(); // yeah I know
return SUCCESS;
ERRHANDLER(ERROR_READ)
freeMem(); // free the buffer, now this will fall
//through to close the file
ERRHANDLER(ERROR_ALLOCMEM)
closeFile();
ERRHANLDER(ERROR_OPENFILE)
return RC_ERROR;
This is a simplified view (the macros I have are quite extensive), but
you get the idea. I find this to be a very intuitive (of course since I
made it up) and useful. There are still a few situations it doesn't
handle well but it really helps, esp. avoiding the forever nested
tests for errors.
George
It was thus said that the Great Uncle Roger once
stated:
and while loops (I rarely use for's), but C
really suffers from a lack
of a general error trapping mechanism that one can invoke to break out
of loops as required. Sometimes I think goto's are the answer but I
can never find an appropriate way to implement it.
errflag := 0 /* is it := in C to assign a value? */
No, it's a simple `='. Comparrisons are done using `=='.
DO WHILE variable < end AND errflag = 0 {
do stuff
variable++ /* I think that increments a variable */
IF error THEN
errflag := 1
ENDIF
LOOP
IF errflag = 1 THEN
do error processing
ENDIF
C does include a `break' keyword, which breaks out of an enclosing
`while', `do' or `for' loop, but it has limited scope:
while(a)
{
while(b)
{
break; /* break out of b */
}
/* still stuck here in a */
}
And if it's an error condition, you often have to set a flag to be
tested
outside the loop anyway:
while(a)
{
rc = processing();
if (rc == ERROR) break;
if (rc == DONE) a = FALSE;
}
if (rc == ERROR) /* handle error */
{
}
It takes quite a bit of thought to avoid this double testing (as I call
it). One way would be to move the error handling code to where you detect
the error and then break out fo the loop:
while(a)
{
rc = processing();
if (rc == ERROR)
{
/* handle error */
break;
}
if (rc == DONE) a = FALSE;
}
Another way is to write code such that errors can only happen in limited
areas. For instance, in C, to allocate memory, you typically do:
p = malloc(SOMESPACE);
if (p == NULL)
{
/* handle out of memory error */
}
I wrote a wrapper function MemAlloc() that calls malloc(), but if
there's
no memory, aborts the program (default case, you can override that
behavior if need be), otherwise returns the memory. So I know that all my
calls to MemAlloc() will succeed (because it never returns if it fails).
Over the past year I've developed what amounts to an exception mechanism
for C that's fairly decent (given the constraints I have to work with), so
it can be done, you just need to be a bit creative when it comes to
coding.
-spc (I've also done templates in C, but that's another story ... )