You are not logged in.

#1 2007-10-21 13:02:46

harlekin
Member
From: Germany
Registered: 2006-07-13
Posts: 408

General question: How to program proper error handling

Hello.
Well, this issue isn't new to me but it's an issue *I* always come across and it seems to be an issue of programming languages in general. This issue is error handling.

I experience most of my projects fail at this (early) stage and I'd like to hear how you handle this problem and how you think it's best handled and why.

First of all I should explain my problem: When you write a program, it is obvious (at least in most cases) that the program has to communicate with the user. Especially in case of an error like if it's trying to read a file and reading fails, the program may stop or may continue running restricted in some matter. The user should be noted as the program may not do what was expected in the first place.

Further more there are different levels of errors. Some are fatal to the program so the program cannot even do what it's supposed to (e.g. program fails to read a essential database file), some are non-fatal. For example the program cannot read its configuration file so it can at least run in "default mode". And some errors are not errors at all, I like to call them notices, e.g. the program likes to retrieve some user input but is choosing a default value after a certain amount of time without interaction. The user should be told that the program was falling back to the default option but this doesn't cause any harm in the program flow. Off course, the definition of fatal error, error, warning, notice or info may be discussed.

My question is how to handle this properly. The different kinds of errors can be handled by assigning each error a value which indicate its importance and you can specify which error values should be expressed to the user and which should just be suppressed.

The more complicated part, at least to me, is how to express those errors to the user. I am most likely about to write a log.h and log.c as I am programming in C and define some functions which write the stdout and/or the an log file. Let's take the case that such an log function would write to an log file *and* to stdout if the program isn't run in "quiet" mode.
The function header would probably look like this:

void log(FILE* handle, bool quiet, const char* format, ...);

The function at least needs a handle to the file it should write to and information whether to log to stdout have to be passed, too. Further it's nice, if you can log in a printf-like manner. So format and an undefined number of arguments follow.

But with this setup it's problematic to me, to log from different object files as every file have to have access to handle and quiet which means that I have to declare them globally. As I like to keep all those settings in an options structure, I have to declare the structure globally, or pass options to almost every function. Both ways are somehow annoying.

Further, as every log function is called with handle and quiet, it would be nice to define ERROR which lets the programmer to call ERROR(format, ...) but how do I declare definitions containing undefined number of arguments?

Off course you could avoid this by just using the log function from main() (or at least main.c) and letting other functions return error values (preferably int) which indicate the error. But this isn't sane either, is it?

So my questions for this awfully long introduction (sorry ^-^) are as follows:
- What do you think are the pro and cons about my way how to handle this and could it be improved? I find this method quite complicated but it's the best I could come up with.
- How do you handle this purpose and why?

Thanks in advance.
harlekin


Hail to the thief!

Offline

#2 2007-10-21 15:17:01

smoon
Member
Registered: 2005-08-22
Posts: 468
Website

Re: General question: How to program proper error handling

I don't see why you have to pass the file handle and the quiet option to the log function. If you're creating a log.c anyway, you could just make the handle static within this file and define a function log_open () which opens your logfile and which you then call in your main function. You can simply do something similar with the quiet boolean.
Here's what it could look like:

static FILE *log_handle = NULL;
static int quiet = 1;

void
set_quiet (int q)
{
    quiet = q;
}

int
log_open (void)
{
    if (log_handle)
        return 0;

    log_handle = fopen (...);
    if (!log_handle)
        return 0;

    return 1;
}

int
log_close (void)
{
    return fclose (log_handle);
}

void
log (const char* format, ...)
{
    if (!quiet)
        fprintf (stderr, ...);

    ...
}

As for your macro question about an undefined number of arguments, here is what the "comp.lang.c FAQ" says:

10.26:  How can I write a macro which takes a variable number of
    arguments?

A:      One popular trick is to define and invoke the macro with a
    single, parenthesized "argument" which in the macro expansion
    becomes the entire argument list, parentheses and all, for a
    function such as printf():

        #define DEBUG(args) (printf("DEBUG: "), printf args)

        if(n != 0) DEBUG(("n is %d\n", n));

    The obvious disadvantage is that the caller must always remember
    to use the extra parentheses.

    gcc has an extension which allows a function-like macro to
    accept a variable number of arguments, but it's not standard.
    Other possible solutions are to use different macros (DEBUG1,
    DEBUG2, etc.) depending on the number of arguments, or to play
    tricky games with commas:

        #define DEBUG(args) (printf("DEBUG: "), printf(args))
        #define _ ,

        DEBUG("i = %d" _ i)

    C9X will introduce formal support for function-like macros with
    variable-length argument lists.  The notation ... will appear at
    the end of the macro "prototype" (just as it does for varargs
    functions), and the pseudomacro __VA_ARGS__ in the macro
    definition will be replaced by the variable arguments during
    invocation.

    Finally, you can always use a bona-fide function, which can
    take a variable number of arguments in a well-defined way.
    See questions 15.4 and 15.5.  (If you needed a macro
    replacement, try using a function plus a non-function-like
    macro, e.g. #define printf myprintf .)

    References: C9X Sec. 6.8.3, Sec. 6.8.3.1.

Offline

#3 2007-10-21 15:32:03

harlekin
Member
From: Germany
Registered: 2006-07-13
Posts: 408

Re: General question: How to program proper error handling

Thank you. I guess this is pretty much solving all my problems. *blush*


Hail to the thief!

Offline

#4 2007-10-21 17:40:27

tam1138
Member
Registered: 2007-09-10
Posts: 238

Re: General question: How to program proper error handling

I am generally a fan of logging everything to stdout (or stderr for emergency stuff) and letting whatever invokes my program decide how to redirect output.

Offline

#5 2007-10-21 18:14:55

Dusty
Schwag Merchant
From: Medicine Hat, Alberta, Canada
Registered: 2004-01-18
Posts: 5,986
Website

Re: General question: How to program proper error handling

You also have the option of taking advantage of syslogd, which probably (I've never used it) provides a similar but more feature-complete interface to the one you've designed.

Dusty

Offline

Board footer

Powered by FluxBB