In a project I am working on, I have defined a basic enum to store a list of the possible errors the application could encounter. However, I would like to find a way to return a string describing the error.
Here's the enumeration I'm using:
enum _library_results_enum{
LIB_SUCCESS = 1,
LIB_FAIL,
LIB_NULL_PARAM,
LIB_MALLOC_ERROR,
LIB_TIMEOUT,
LIB_CONNECTION_CLOSED
}
If a function returns a result other than LIB_SUCCESS, then ideally I would like to be able to just say:
printf("Error Description: %s\n", ERROR_DESCRIPTIONS[RESULT]);
To handle that I would imagine I need a static const *char[] to house an array of all descriptions. However, the enum values do not start at zero (0) and eventually I might add some negative values to this enum. Thus, using an array of strings isn't really an option. What else could I do to handle this?
I have considered just creating a function which uses a switch statement to return back a description. However, this is really just a fallback solution if there is not a better option.
Edit: To better clarify, what I need is a way to associate result codes within an enumeration to a string describing them.
Your proposed fallback solution of a function that returns strings for each of the discontinuous error code looks like a good solution to me.
A nice solution to keep enum and messages lined up and to ensure that each enumerated value has its message are X macros. (I now see that Weather Vane has beaten me to this answer by posting a link.)
Here's how that might look applied to your problem:
#include <stdlib.h>
#include <stdio.h>
#define ERROR_CODES(X) \
X(0, LIB_SUCCESS, "No error at all!") \
X(10, LIB_FAIL, "An error occurred") \
X(20, LIB_NULL_PARAM, "Illegal null param") \
X(30, LIB_MALLOC_ERROR, "Allocation failed") \
X(40, LIB_TIMEOUT, "Connection timed out") \
X(-5, LIB_CONNECTION_CLOSED, "Connection closed") \
#define ERROR_ENUM(ID, NAME, TEXT) NAME = ID,
#define ERROR_TEXT(ID, NAME, TEXT) case ID: return TEXT;
enum {
ERROR_CODES(ERROR_ENUM)
};
const char *error_msg(int code)
{
switch (code) {
ERROR_CODES(ERROR_TEXT)
}
return "Unknown error";
}
int main()
{
puts(error_msg(LIB_TIMEOUT));
puts(error_msg(LIB_CONNECTION_CLOSED));
puts(error_msg(LIB_SUCCESS));
return 0;
}
Related
I made an array based Stack data structure in C.
Furthermore I wanted to implement error handling to allow other people to use this class as well for there own uses, but the best I have come up is for the method to return an enum and then have the user send the value into a "printErrorMessage" function where it to prints a message to terminal.
/**enum with all the possible error messages**/
typedef enum stackError_t {SUCESS, FAILED_MEMORY_ALLOCATION, FAILED_STACK_DOUBLEUP, NEGATIVE_VALUE, STACK_EMPTY}STACK_ERROR_MESSAGE;
/**prints error message to terminal**/
void printErrorMessage(STACK_ERROR_MESSAGE *message){
switch(*message){
case SUCESS : printf("Nothing went wrong!");break;
case FAILED_MEMORY_ALLOCATION : printf("Not enough memory!");break;
case FAILED_STACK_DOUBLEUP : printf("Stack has failed to doubleUP!");break;
case NEGATIVE_VALUE : printf("Negative Value should have not been entered!");break;
case STACK_EMPTY : break;
}
/**example method that can return an error**/
STACK_ERROR_MESSAGE makeStack(Stack **stack, const uint32_t length, const uint32_t bytes)
The other was is for users to pass in a enum pointer to the function
void * popStack(Stack *stack, STACK_ERROR_MESSAGE *message)
and then call "printErrorMessage" function if anything goes wrong.
I was hoping to get better ideas then to use a enum for this error handling as it seems a little clunky. Plus I would need to check in every method if the Stack pointer has been initialized and add an error enum like "STACK_NOT_INITIALIZED".
TLDR - What other ways are there to do error handling in C? And if you use enums what types of errors would you add?
And I apologize in advance if this question has been asked.
Thank You for your time.
Regards,
Dagar
You could create a char[][] array (an array of strings) aligned to STACK_ERROR_MESSAGE enum, so that whenever you get an error you are able to use the enum item as an index to access the desired string:
/**enum with all the possible error messages**/
typedef enum stackError_t
{
SUCCESS,
FAILED_MEMORY_ALLOCATION,
FAILED_STACK_DOUBLEUP,
NEGATIVE_VALUE,
STACK_EMPTY,
MAX_STACK_ERROR
} STACK_ERROR_MESSAGE;
static const char *stackErrorStrings[]
{
"SUCCESS",
"FAILED_MEMORY_ALLOCATION",
"FAILED_STACK_DOUBLEUP",
"NEGATIVE_VALUE",
"STACK_EMPTY",
"MAX_STACK_ERROR"
};
/**prints error message to terminal**/
void printErrorMessage(STACK_ERROR_MESSAGE *message)
{
if( message && *message > SUCCESS && *message < MAX_STACK_ERROR){
printf("Stack failed with error %s\n", stackErrorStrings[*message]);
}
}
This method is mainly suitable for those situations in which the errors don't vary too much during the lifetime of the software, because the enum and the string array have to be kept aligned.
As you can see, it allows a "standardization" of the error message string (in which I chose to print nothing in case of success).
I'm writing my own enums-based backtrace. Basically each function call will append it's error to a pre-defined stack which will eventually include all errors across all function calls.
I want to create an efficient way to parse it. In the end I got int backtrace[] with enum values from all over my codebase, and I'd like to relate each enum value to it's name.
This should of course be done post-failure (not at runtime), so what I'm missing is a way, maybe as a part of the compilation step, to dump all my enums and there values to a file. Then i can write a script that parse the errors.
Is there an easy (cross-platform) static tool that does that?
Not sure how you log the errors, but how about:
typedef enum
{
E_SUCCESS = 0,
E_FAIL,
...
} error_t;
typedef struct
{
error_t code;
char * error_name;
} backtrace_entry_t;
backtrace_entry_t backtrace[..];
#define FUNC_EXIT(error_code__) \
do { \
backtrace[func_id].code = (error_code__); \
backtrace[func_id].error_name = #error_code__; \
} while (0)
Then, when you call FUNC_EXIT(E_SUCCESS);, you'll get for the backtrace for the function to be: {.code = 0, .error_name = "E_SUCCESS"}
The problem is, you can't get the right name if you call FUNC_EXIT(var);, where var is some local variable.
Another option, although still not an automagical one:
typedef enum
{
E_SUCCESS = 0,
E_FAIL,
...
NOF_ERROR_CODES
} error_t;
#define MAP_E_CODE_TO_NAME(error_code__) [error_code__] = #error_code__
const char * error_to_name_mapping[NOF_ERROR_CODES] = {
MAP_E_CODE_TO_NAME(E_SUCCESS),
MAP_E_CODE_TO_NAME(E_FAIL),
...
};
Will give a const char * array with {"E_SUCCESS", "E_FAIL", ...}, which you can use like this:
printf("The name of error code %d is '%s'", error, error_to_name_mapping[error]);
The problem here is that you have to have positive value to errors with increasing values.
While adapting some given interface, I came across the problem of extending the use of a header file with a lot of #defines.
What I have is something like this:
#define STATUS_OK 0x00
#define STATUS_FAIL 0x01
#define STATUS_WAIT 0x02
#define STATUS_ILLEGAL 0x03
#define STATUS_FULL 0x04
...
There are a lot of definitions like this, and I am quite happy about it, because I didn't had to write them all.
However, while I can nicely use them for switch, if and other statements as a replacement for 0x00 and so on, I now would like to have the opposide direction.
So, having 0x00, I would like to print out the identifier "STATUS_OK".
As far as I know, this is not possible, but what would be a good workaround to make it possible?! Would it be possible to setup an array like this:
arrayNames[STATUS_OK] = _STATUS_OK_
Whereby STATUS_OK would resolve to 0x00 and _STATUS_OK_ would resolve to "STATUS_OK"?
Further, I am looking for a solution, which uses as little memory, as possible to do this.
This would be what I would like to be able to do:
prinf("%s",resolve(0x00));
-> "STATUS_OK"
I hope, I made clear what I am looking for.
Edit:
Thanks to all for, the quick and useful responses! I'll work with Larsmans solution and might try to combine it with the one of qrdl. May take a while, I'll replace this edit, when it is done.
You can use a little macro wizardry and a stringize operator of the preprocessor to do it. Take a look:
#include <stdio.h>
#define STATUS_OK 0x05
#define STATUS_BAD 0x09
#define LOOKUP_CASE(x) case x: return #x
const char *lookup_name(int val) {
switch(val) {
LOOKUP_CASE(STATUS_OK);
LOOKUP_CASE(STATUS_BAD);
default: return "<UNDEFINED>";
}
return NULL;
}
int main(void) {
printf("%s\n", lookup_name(STATUS_OK));
printf("%s\n", lookup_name(STATUS_BAD));
return 0;
}
The example is self-explanatory, except for the LOOKUP_CASE macro. It uses the # operator to produce a string constant that corresponds to its operand, letting you avoid repeating the name of the #define-d constant twice.
Here is a link to ideone with this working example.
Use X-Macros, although it will require changing your original header file
You can do something like this:
const char *status_str(int s)
{
switch(s)
{
case STATUS_OK:
return "STATUS_OK";
/* And so on and so forth */
}
}
It's not possible to get name of the identifier from its value. Because the identifiers are no longer available after the pre-processing and compiler has no knowledge about them.
However, you can try to store their names in an array or some other trick similar to that.
One easy solution is to write two very simple code generators. If you store your identifiers in a text file with the simple format
identifier value
e.g.
STATUS_OK 0x00
STATUS_FAIL 0x01
then two simple Awk scripts can generate a header with the #defines and a C module with the strings from that. For the headers:
BEGIN {
print("#ifndef _STATUSCODES_H");
print("#define _STATUSCODES_H");
}
{ printf("#define %s %s\n", $1, $2) }
END { print("#endif"); }
For the mapping back to strings:
BEGIN {
print("#include \"statuscodes.h\"");
print("char const *status_string(int status)");
print("{");
print(" switch (status) {");
}
{ printf(" case %s: \"%s\"\n", $2, $1); }
END {
print(" }");
print("}");
}
Then let your Makefile generate the module and header when the table of identifiers changes.
I don't think there is a solution for your problem without using switch to check for every value or making a full list with the names:
char *s_names[] = {
"STATUS_OK",
"STATUS_FAIL",
...
}
Now you can simply access the strings by the index (which is the error code):
printf("%s", s_names[0x00]); // prints "STATUS_OK"
printf("%s", s_names[STATUS_OK]); // prints "STATUS_OK" too
This will work if you have the value (or the macro) but if you don't want to waste so much space for a whole list you can use this macro:
#define MACRO_TO_STRING(x) #x
Now you can convert the macro to a string but not the value to a string:
printf("%s", MACRO_TO_STRING(STATUS_OK)); // prints "STATUS_OK"
printf("%s", MACRO_TO_STRING(0x00)); // but this doesn't work: prints "0x00"
I would like to force a functions parameters to accept only specific definitions. For example, consider #define OUTPUT 1, #define INPUT 0 and void restrictedFunction(int parameter); .
How would I force restrictedFunction(int parameter) to accept only OUTPUT or INPUT?
I would also like to take into consideration that another definition may have the same value, for example, #define LEFT 1 and #define RIGHT 0.
So in this case I would like restrictedFunction(int parameter) to be able to accept only OUTPUT and INPUT specifically.
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
void restrictedFunction(IO_Type parameter) { ... }
It doesn't absolutely force the use of the values (the compiler will let someone write restrictedFunction(4)), but it is about as good as you'll get.
If you truly want to force the correct type, then:
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
typedef struct { IO_Type io_type } IO_Param;
void restrictedFunction(IO_Param parameter) { ... }
In C99 or later, you could call that with:
restrictedFunction((IO_Param){ INPUT });
This is a compound literal, creating a structure on the fly. It is not entirely clear that the structure type really buys you very much, but it will force the users to think a little and may improve the diagnostics from the compiler when they use it wrong (but they can probably use restrictedFunction((IO_Param){ 4 }); still).
What this means is that your restrictedFunction() code should be ready to validate the argument:
void restrictedFunction(IO_Type io_type)
{
switch (io_type)
{
case INPUT:
...do input handling...
break;
case OUTPUT:
...do output handling...
break;
default:
assert(io_type != INPUT && io_type != OUTPUT);
...or other error handling...
break;
}
}
You could use an enum.
typedef enum TrafficDirection { INPUT = 0, OUTPUT = 1 } TrafficDirection;
restrictedFunction(TrafficDirection direction);
of course, this isn't perfect. You can still pass any int to it as long as you use a cast.
restrictedFunction((TrafficDirection) 4);
You don't get quite as much protection as you might like, but you can do:
enum func_type { INPUT, OUTPUT };
void restrictedFunction( enum func_type parameter );
You can use a wrapper to validate the argument:
#define restrictedFunction(x) do { \
static_assert((x) == INPUT || (x) == OUTPUT); \
assert(!strcmp(#x, "INPUT") || !strcmp(#x, "OUTPUT")); \
restrictedFunction(x); \
} while(0)
Notes:
This assumes restrictedFunction() returns a void. If it returns a value which you actually use, you'll need something like gcc's compound statement http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html. Or--better--you can use BUILD_BUG_ON_ZERO (see What is ":-!!" in C code?), which I keep forgetting about, because it doesn't seem to work with C++.
The do ... while(0) is to "swallow the semi-colon"; not really relevant here.
static_assert() is a compile-time assert; there are many variants available. Here is a link to one, https://stackoverflow.com/a/9059896/318716, if you don't have your own handy.
assert() is the standard run-time assert.
With gcc 4.1.2, and my version of static_assert(), you can replace the run-time assert() with a compile-time assert when the two !strcmp()'s are replaced with ==; see example below. I haven't tested this with other compilers.
x is only used once in the macro expansion, since the first four references are only used at compile-time.
When your actually define your function, you'll have to add parentheses to disable the macro expansion, as in:
void (restrictedFunction)(int x){ ... }
Also, if your code has a special case (whose code doesn't?) where you need to call restrictedFunction() with the argument foo, you'll need to write:
(restrictedFunction)(foo);
Here is a complete example, which puts a wrapper around the standard library function exit():
#include <stdlib.h>
#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum{EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}
#define exit(x) do { \
ASSERTM((x) == EXIT_SUCCESS || (x) == EXIT_FAILURE, value); \
ASSERTM(#x == "EXIT_SUCCESS" || #x == "EXIT_FAILURE", symbol); \
exit(x); \
} while(0)
int main(void) {
exit(EXIT_SUCCESS); // good
exit(EXIT_FAILURE); // good
exit(0); // bad
exit(3); // doubly bad
}
If I try to compile it, I get:
gcc foo.c -o foo
foo.c: In function 'main':
foo.c:17: error: enumerator value for 'symbol_ASSERT_line_17' is not an integer constant
foo.c:18: warning: division by zero
foo.c:18: error: enumerator value for 'value_ASSERT_line_18' is not an integer constant
foo.c:18: error: enumerator value for 'symbol_ASSERT_line_18' is not an integer constant
I'm writing a simple parser to read the config file.The config.h interface have only three
main functions they are in brief as follows,
config_init();
config_dinit();
config_parse();
config_read_value();
My question is those functions will emit different type of errors , for a example,
config_init() emit , FILE_NOT_FOUND,FILE_EOF_ERROR,FILE_OPEN_ERROR, ...
config_dinit() emit , NOT_INIT_ERROR ,
config_parse() emit , PARSE_ERROR, OVERFLOW_ERROR, INVALID_CHARACTER_FOUND_ERROR,...
config_read_value() emit, SECTION_NOT_FOUND,KEYWORD_NOT_FOUND,OVERFLOW_ERROR,NOT_INITIALIZED_ERROR,INVALID_STATE_ERROR,... etc.
Then I create enums for each function, for by using these names ,
enum Config_ParseError{...} , enum Config_InitError{...} ,enum Config_ReadValueError{..}
etc.
Some enum values are overlapping each other and hit "compiler error" too. like
OVERFLOW_ERROR,
I'm opening for your suggestions,
and I have done a quick research on the google and found that most popular IRC client
source code have defined the enums like this,
enum {
CMDERR_OPTION_UNKNOWN = -3, /* unknown -option */
CMDERR_OPTION_AMBIGUOUS = -2, /* ambiguous -option */
CMDERR_OPTION_ARG_MISSING = -1, /* argument missing for -option */
CMDERR_UNKNOWN, /* unknown command */
CMDERR_AMBIGUOUS, /* ambiguous command */
CMDERR_ERRNO, /* get the error from errno */
CMDERR_NOT_ENOUGH_PARAMS, /* not enough parameters given */
CMDERR_NOT_CONNECTED, /* not connected to server */
CMDERR_NOT_JOINED, /* not joined to any channels in this window */
CMDERR_CHAN_NOT_FOUND, /* channel not found */
CMDERR_CHAN_NOT_SYNCED, /* channel not fully synchronized yet */
CMDERR_ILLEGAL_PROTO, /* requires different chat protocol than the active server */
CMDERR_NOT_GOOD_IDEA, /* not good idea to do, -yes overrides this */
CMDERR_INVALID_TIME, /* invalid time specification */
CMDERR_INVALID_CHARSET, /* invalid charset specification */
CMDERR_EVAL_MAX_RECURSE, /* eval hit recursion limit */
CMDERR_PROGRAM_NOT_FOUND /* program not found */
};
it defines enum without any name, is that a good style?Then why what are the reasons for
that?
Seriously need some more good naming decisions. Please don't hurt me I just only
start reading "writing beautiful C code" book.
Thanks In Advance.
Sandun.
I'm usually a fan of one set of error returns for an entire library. This way in consumers they don't have to worry about "was the -1 bad input to X or could not connect to Y".
I'm also a fan of E_ prefixes, but really any will do:
enum _config_error
{
E_SUCCESS = 0,
E_INVALID_INPUT = -1,
E_FILE_NOT_FOUND = -2, /* consider some way of returning the OS error too */
....
};
/* type to provide in your API */
typedef enum _config_error error_t;
/* use this to provide a perror style method to help consumers out */
struct _errordesc {
int code;
char *message;
} errordesc[] = {
{ E_SUCCESS, "No error" },
{ E_INVALID_INPUT, "Invalid input" },
{ E_FILE_NOT_FOUND, "File not found" },
....
};
I'm of the opinion that is good style. The CMDERR_ prefix groups together the related error codes (assuming they're related to some kind of "command invocation/execution")
Since all of your examples seem to be related to your config functions, I'd just go with a one enum definition using CONFIG_ prefix (or CFG_ for brevity).
enum Config_Errors {
CONFIG_FILE_NOT_FOUND,
CONFIG_FILE_EOF_ERROR,
CONFIG_FILE_OPEN_ERROR,
//etc.
};
The reasoning behind the common prefix is that when using an enumerated type you want to make it clear that the members of the type all belong to the same group.
The CMDERR_ prefix in the IRC client source code is a good style, but defining enum without any name is not a good style. Not good because you cannot say it is an enum type, only an integer type like below:
CMDERR function1();
int function1(); // actually returning CMDERR unnamed enum
and you cannot define variable using the enum type like below:
CMDERR errResult;
int errResult; // actually errResult is CMDERR unnamed enum