Thread: status/error handling in C

  1. #1
    Registered User
    Join Date
    Apr 2004
    Posts
    3

    status/error handling in C

    Hello all,

    I'm trying to find an efficient way to capture errors, report it and act on it. At the moment I have an enum of error codes and a function which prints out switching on the error code. This is oK as I don't have to act on every type of error returned by a function, but is inefficient in the sence I would like to be able to report more specifically what the error is.

    e.g. at the moment my code can have something like

    ERROR_STATUS status = STATUS_OK;

    status = some_function_call();

    if (status == STATUS_OK)
    do_something;
    else
    report_status(status);

    So status may be DEVICE_ERROR and report_status(status) may print out "ERROR: Device error". This is OK in the sense that I can group a bunch of error conditions to a single error code, however I would like to be more specific in what report_status returns, e.g. "ERROR: Device not found" or "ERROR: Device not ready" or "ERROR: Device not supported" etc.

    So I'm looking for an efficient way of avoiding lots of if statement clutters when essentially I will be acting on anything to do with a device error with the same action, and yet be able to report more precicely what the error was. On a more advanced stage I would like to be able to pass in arguments in the printf. E.g "Error: Invalid device header. Found X. Expected Y" where X and Y are passed in.

    I know C (not C++ or C#) does not have any specific error or exception handling functions and clever routines have to be written. Unfortunately, as a newbie I'm not clever yet

    Any suggestions and poiters are most welcome.

    Thanks in advance,
    Monty

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    That's a detailed error handling scheme for a self proclaimed "newbie". Are you sure you aren't trying to do too much, too soon?

    >however I would like to be more specific in what report_status returns
    The more specific you get, the more error codes you will have. One way to simplify this is to have a generic error code and then a bit field that can be fiddled with to get something more specific. But if possible, you want to be able to map the error codes to an array of strings so that reporting is as simple as indexing an array.

    >So I'm looking for an efficient way of avoiding lots of if statement clutters
    If you can stand a bunch of error codes then the most efficient solution would be a table lookup like I described above. Something simple would be:
    Code:
    enum error {
      ERROR0,
      ERROR1,
      ERROR2,
      ERROR3,
      ERROR4
    };
    
    const char *errors[] = {
      "Error: ERROR0",
      "Error: ERROR1",
      "Error: ERROR2",
      "Error: ERROR3",
      "Error: ERROR4"
    };
    
    void report ( enum error e_code )
    {
      fprintf ( stderr, "%s\n", errors[e_code] );
    }
    My best code is written with the delete key.

  3. #3
    Registered User
    Join Date
    Apr 2004
    Posts
    3
    Prelude, thanks. Someone mentioned to me that you can't have enough printfs as a starter programmer as it helps your debug your problems. That got me thinking, well if I'm going to have lots of printfs why not actually make the time and effort count and actually have a generalised error handling function, hence my little project. As for your solution, it goes to solve the problem to some extent. I can't see how I would be able to pass in parameters. All the errors will ne constant strings right?

  4. #4
    /*enjoy*/
    Join Date
    Apr 2004
    Posts
    159
    I counsel you again to developpe the procedure of prelude because you can deceive you easily
    if you don't put a talking variable of mistake

  5. #5
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >why not actually make the time and effort count and actually have a generalised error handling function
    You would be surprised at how difficult it is to write generic error handling code. Most of the time a few select functions/macros are reused, but the rest of the code would be application specific.

    >I can't see how I would be able to pass in parameters.
    That's a more advanced technique. You can either use a macro, or a function with a variable length argument list. Here is a quicky panic macro:
    Code:
    #define panic(msg) fprintf(stderr, "%s - %d : %s\n", __FILE__, __LINE__, msg);
    And a variable length error function:
    Code:
    #include <stdio.h>
    #include <stdarg.h>
    
    void error ( char *fmt, ... )
    {
      va_list args;
    
      fprintf ( stderr, "Error: " );
      va_start ( args, fmt );
      vfprintf ( stderr, fmt, args );
      va_end ( args );
      fprintf ( stderr, "\n" );
    }
    Both of these are obscure enough to be written with care. Macros and variable length argument lists are two highly error prone areas in C, but they are also very powerful and flexible if you use them right.

    >All the errors will ne constant strings right?
    Not necessarily. Applications that use different languages will usually store the error messages in a file, read them in at startup, and then use them. String literals are reserved for more inflexible messages or for smaller programs.
    My best code is written with the delete key.

  6. #6
    Registered User
    Join Date
    Apr 2004
    Posts
    3

    Talking

    Thanks prelude. I've tested both your methods with slight mod. Here's the working code if anyone is interested.


    typedef enum errors{
    DEVICE_ERROR,
    DEVICE_NOT_FOUND,
    UNKNOWN_DEVICE,
    DEVICE_NOT_READY,
    STATUS_OK
    }STATUS_T;

    const char *error_msgs[] = {
    "Error: Device error",
    "Error: Device_not_found",
    "Error: Unknown device",
    "Error: Device not ready",
    "Error: Status OK"
    };

    void report_status (STATUS_T e_code)
    {
    printf ("%s\n", error_msgs[e_code] );
    }


    void report_status_with_args ( char *fmt, ... )
    {
    va_list args;
    va_start ( args, fmt );
    vprintf (fmt, args );
    va_end ( args );
    }

    STATUS_T which_error()
    {
    STATUS_T this_error = UNKNOWN_DEVICE;

    return this_error;
    }

    STATUS_T find_device(char *devStr, char *rtrnStr)
    {
    char *devName = "FLOPPY";
    STATUS_T status = STATUS_OK;
    if (strcmp(devStr, devName)==0)
    {
    strcpy(rtrnStr,devStr);
    }
    else
    {
    strcpy(rtrnStr,devName);
    status = UNKNOWN_DEVICE;
    }
    return status;
    }


    int main (void)
    {
    STATUS_T error = STATUS_OK;
    char *device = "SCANNER";
    char *retDev = malloc(sizeof(char *));

    error = which_error();

    report_status(error);

    error = find_device(device, retDev);

    report_status_with_args("\n %s. Expected: %s. Got: %s\n", error_msgs[error], device, retDev);

    return 0;
    }

  7. #7
    Registered User
    Join Date
    Jan 2003
    Posts
    648
    Your code is bugged with buffer overflows. First off, you allocate an array of characters thats sizeof(char *) long (4 bytes on most computers). That in itself makes no sense at all. Then you strcpy it with a bigger string, creating a buffer overflow. Use strncpy instead and rethink your string allocation.

Popular pages Recent additions subscribe to a feed