Each source file of my library (libA) includes an in_err.h file.
This file defines an enum for every possible error, and an array of string describing the corresponding error.
There is a function get_err_mess() which returns the error message corresponding to the error enum.
in_err.h
typedef enum {
E_ERR_NOERROR = OK, //OK=0
E_ERR_1 = E_ERR_BADPARAM,
...
E_ERR_MAX
} ERROR;
const char *error_description[] = {
"No error.",
"Bad parameter.",
...
"Max error enum reached.",
};
const char * get_err_mess(ERROR err){
...
return err_mess;
}
Every functions of my library (libA) returns an ERROR type.
libA.a
#include "in_err.h"
ERROR func1()
{
ERROR err = OK;
...
return err
}
The main program calls functions from libA and displays error message if any.
main.c
#include "in_err.h"
#include "headerfromlibA.h"
int main()
{
ERROR err = OK;
err = func1()
if (!err){
err = func2()
}
if(err){
printf("Error: %s\n", get_err_mess(err));
}
return err;
}
Now I want to make another library (libB) with the same kind of error management but with its own types of errors.
My problem is that I would have two get_err_mess() functions with potentially the same error id.
I'd like to have a single get_err_mess() to manage errors from libA and libB.
What would you recommend ?
The only solution I see is to set a range of error for each library... but I don't like it
CodePudding user response:
Basic idea: return a 16-byte struct (UNIFORM_ERROR
below) on the stack.
err.h
:
#pragma once
typedef const char *(*err_msg_func)(int err);
typedef struct {
err_msg_func err_to_msg;
const char *name;
} ERR_SRC;
typedef struct {
int code;
const ERR_SRC* src;
} UNIFORM_ERROR;
static inline const char *err_msg(UNIFORM_ERROR err) {
return err.src->err_to_msg(err.code);
}
liba.h
:
#pragma once
#include "err.h"
typedef enum {
EA_ERR_NOERROR = 0,
EA_ERR_BADPARAM,
EA_ERR_PERMISSION,
EA_ERR_MAX
} A_ERROR;
UNIFORM_ERROR a_func();
liba.c
:
#include "liba.h"
static const char *error_msg[] = {
"No error",
"Bad parameter",
"No permission",
"Max error enum reached"
};
static const char *a_error_msg(int code) {
return error_msg[code];
}
static const ERR_SRC a_err_src = {
a_error_msg,
"a"
};
static UNIFORM_ERROR mkerr(A_ERROR code) {
UNIFORM_ERROR err = {code, &a_err_src};
return err;
}
UNIFORM_ERROR a_func()
{
return mkerr(EA_ERR_BADPARAM);
}
libb.h
:
#pragma once
#include "err.h"
typedef enum {
EB_ERR_NOERROR = 0,
EB_ERR_NOTFOUND,
EB_ERR_MAX
} B_ERROR;
UNIFORM_ERROR b_func();
libb.c
:
#include "libb.h"
static const char *error_msg[] = {
"No error",
"Not found",
"Max error enum reached"
};
const char *b_error_msg(int code) {
return error_msg[code];
}
static const ERR_SRC b_err_src = {
b_error_msg,
"b"
};
static UNIFORM_ERROR mkerr(B_ERROR code) {
UNIFORM_ERROR err = {code, &b_err_src};
return err;
}
UNIFORM_ERROR b_func()
{
return mkerr(EB_ERR_NOTFOUND);
}
main.c
:
#include <stdio.h>
#include "liba.h"
#include "libb.h"
#include "err.h"
int main()
{
UNIFORM_ERROR err;
err = a_func();
printf("Error %d from %s: %s\n", err.code, err.src->name, err_msg(err));
err = b_func();
printf("Error %d from %s: %s\n", err.code, err.src->name, err_msg(err));
}
output:
Error 1 from a: Bad parameter
Error 1 from b: Not found