Functions returning Error codes or actual info

Larry Campbell campbell at redsox.bsw.com
Thu Sep 13 12:44:26 AEST 1990


Magic Values are a Bad Thing.  You have to remember to check the returned
value to see if it's a Magic Value, and if you forget to check (a very
common mistake), your code can break in mysterious ways.  For example, who
*really* bothers to check *every* call to malloc to see if the returned
value is NULL?  Magic Values also mean you often have to pervert the type
system -- like making fgetc() return an int instead of a char (what
beginning C programmer has not made the mistake of declaring its result as a
char?)

A much better approach is to use exceptions, a la Modula-3.  Functions are
assumed to *always* return the asked-for value.  If an error occurs, an
exception is raised; *if* you're prepared to check for the error, you
declare an exception handler which gets control; otherwise, the default
exception handler takes over, which usually just tells you the name of the
exception, and where it occurred, and dumps core.

I have implemented a portable exception handling facility for C that we are
using in all our projects here and have found to be very useful.  Using its
syntax, here is an example:

    1	    TRY
    2	        FOO x;
    3	        x = get_next_foo();
    4	        fondle_foo(x);
    5	    EXCEPT
    6	        CASE(Exc_No_More_Foos)
    7		    printf("all foos fondled!\n");
    8		    return;
    9		CASE(Exc_Foo_Quota_Exceeded)
   10		    printf("buy more foos!\n");
   11		    exit(1);
   12	    ENDTRY

get_next_foo() is defined *always* to return a FOO, or to raise an
exception.  If get_next_foo() runs out of FOOs, for example, it just says:

    RAISE(Exc_No_More_Foos)

This will cause control to pass immediately to line 7 above.  This RAISE
statement could occur inside get_next_foo(), or inside any routine called by
get_next_foo().

If an exception is raised that is not listed in the EXCEPT clause (in the
present example, any exception other than Exc_No_More_Foos or
Exc_Foo_Quota_Exceeded), the stack is unwound until a TRY-EXCEPT clause is
found that wants to catch the exception.  If no willing handler is found, the
default exception handler is invoked (which in our implementation prints the
name of the exception and the source file name and line number where it was
raised, and then dumps core.)

Using this facility, it is "safe" not to bother to check for the success or
failure of a function call; by "safe" I mean that the behavior of the
program is well-defined -- it crashes immediately with a message that tells
you exactly what happened.  If your functions return Magic Values and you
forget, or just don't bother, to check for them, then when they fail, your
program's behavior becomes undefined.
-- 
Larry Campbell                          The Boston Software Works, Inc.
campbell at redsox.bsw.com                 120 Fulton Street
wjh12!redsox!campbell                   Boston, MA 02109



More information about the Comp.lang.c mailing list