Bill
Bill

Reputation: 2349

Please critique error-reporting approach in C

While working on relatively straightforward C code at work today, I began day-dreaming a little and wrote up the following library for effectively producing error messages. The jury is still out - in my mind, at least - whether this is a more effective approach than simply adapting perror with errno to your purposes... It doesn't even need to be a "library" at all, rather just a set of macros.

For now, I'm calling the library elib:

elib.h

#ifndef _ELIB_H_
#define _ELIB_H_

struct ErrorMap {
    void (*fp);
    int errorCode;
    char * message;
};

#define eperror(...) fprintf(stderr,  ##__VA_ARGS__)
char * getErrorMsg(struct ErrorMap *, void (*fp), int);

#endif /* _ELIB_H_ */

elib.c

#include <stdlib.h>
#include "elib.h"

char * getErrorMsg(struct ErrorMap * errorMap, void (*fp), int code)
{
    int i;
    // TODO: Replace naive search
    for (i=0; errorMap[i].fp != NULL; i++)
    {
        if (errorMap[i].fp == fp && errorMap[i].errorCode == code)
        {
            return errorMap[i].message;
        }
    }
    return NULL;
}

test.c (sample app "xyzlib")

#include <stdio.h>
#include <string.h>

#include "elib.h"

int xyzlib_openFile(int);
int xyzlib_putStuff(char *);

static struct ErrorMap xyzlib_ErrorMap [] = {
    {xyzlib_openFile, -1, "Argument is less than 3"},
    {xyzlib_putStuff, -1, "Argument is NULL"},
    {xyzlib_putStuff, -2, "Length of argument is 0"},
    {xyzlib_putStuff, -3, "Stuff is too long"},
    {NULL, 0, NULL}
};


int xyzlib_openFile(int fd)
{
    if (fd > 3)
    {
        return (-1);
    }

    // open a file.. or something.

    return 0;
}

int xyzlib_putStuff(char * stuff)
{
    if (stuff == NULL)
    {
        return (-1);
    }

    if (strlen(stuff) == 0)
    {
        return (-2);
    }

    if (strlen(stuff) > 3)
    {
        return (-3);
    }

    // do something ...

    return (0);
}


int main(int argc, char ** argv)
{
    int code;

    if (argc != 2)
    {
        printf("Usage: %s <arg>\n", argv[0]);
        return 1;
    }

    code = xyzlib_putStuff(argv[1]);

    if (code < 0)
    {
        eperror("Error: %s\n", getErrorMsg(xyzlib_ErrorMap, xyzlib_openFile, code));    
    }
}

Basically, you define/register the return codes in the ErrorMap table, and if you ever receive an error indication (response value < 0), then the getErrorMsg will look through the registered table for the corresponding code and function to get the proper message. I think the value is that for a given library taking this approach to error reporting, error codes can be defined per function (rather than globally) - simplifying management of all the codes.

However, in addition to a small overhead looking up the appropriate message, all C code taking this approach would require every function (that doesn't return non-negative integers) to return ints, and then use the first argument to be a pointer to the return value -- Slightly non-idiomatic but commonly used.

Let's say the target market is software for high-reliability embedded devices (but not terribly resource-constrained).

Any thoughts? Thanks in advance.

Upvotes: 2

Views: 159

Answers (1)

Inso Reiges
Inso Reiges

Reputation: 1929

I don't really see a point in this, sorry. Maybe that's because of how i work with error codes in C. Basically i define error values as a part of the interface of a single module. The error value between modules do collide, i.e. i don't care if two modules have the same numerical value for their different error codes. To get strong type-checking for different enums i usually wrap them into a struct. But i never really care about making error codes unique for each function which is what your approach seems to be about.

Again, this is my specific, but i never really felt the need to do otherwise. Error codes defined for the whole module usually fit to be passed between procedures that implement this module. Now what if your approach could actually be mapped on a module boundary instead of the function? :)

Upvotes: 1

Related Questions