S
Spacen Jasset
The main two desirable things I feel error handling should provide are
these:
1) Debugging and diagnostic aid
2) User feedback
One method that is used a fair amount it to 'say' that all functions must
return an error code of a standard type, for example tError. Where tError is
typedefed as a long int. A list of error codes may then be defined in a
global header file, or perhaps upper bits of tError may indicate a module
code, and lower bits a module specific error code.
Example:
tError OpenResource( ... )
{
...
return MAKE_ERROR( MOD_RESOURCE, RESOURCE_INVALID_PATH );
}
Here MAKE_ERROR fuses the error information together to form the error
return code of type tError. Unfortunately there is no room for additional
debugging information, such as __FILE__, or __LINE__ which could be very
useful, so this method fails feature (1) somewhat.
There are other ways that I don't favour e.g: Set a global error code.
either
like C's errno. or using a GetError() / SetError() approach. And there is
setjmp and longjump.
Here is a proposed method, which seems somewhat unwieldy too ( an
abomination really ). It does have some advantages though, namely:
1) Could work with threads
2) Provides line and file number, as well as any other desirable information
to be added to the 'error' structure.
On the down side:
1) It's a bit of a mess
2) Wouldn't work in environments where global variables aren't allowed.
What I was trying to do here is a universal ( well across a single large
project ) error handling mechanism and debugging information to go with
that, namely file and line numbers. Perhaps someone can suggest a good
alternative method to yield these things. Using int return codes to API
functions, and a macro to set fields in a global structure might be more
sensible, but would fall apart in the presence of multi threading.
NB- The UUID is there so that a new set of error codes can be defined
without recompiling any core code.
--------- error.h --------
struct sError
{
char *uuid;
char *name;
int code;
int specific;
char *file;
long line;
} Error;
typedef struct sError *tError;
static tError MakeError( tError mod, int code, int specific, char *file,
long line )
{
mod->code = code;
mod->specific = specific;
mod->file = file;
mod->line = line;
return mod;
}
/* Declare a struct in the C file to hold the error information */
#define ERROR_DECALRE_MOD( mod, uuid, name ) static struct sError mod = {
uuid, name }
/* Set the error information and return a pointer to it - use like this:
return ERROR_GENERAL( ParserModule, eParse_BadlyFormedConstant );
*/
#define ERROR_SPECIFIC( mod, code ) MakeError( &mod, code, 1, __FILE__,
__LINE__ )
#define ERROR_GENERAL( mod, code ) MakeError( &mod, code, 0, __FILE__,
__LINE__ )
#define ERROR_GET_CODE( err ) ((err) ? (err)->code : 0)
/* Each module has some sort of UUID so that a user interface can locate
user error messages and diplay them */
#define ERROR_GET_MOD( err ) ((err) ? (err)->uuid : eMod_Unknown)
#define ERROR_IS_MOD( err, uuid ) ((err) ? !strcmp((err->uuid), (uuid)):
0 );
#define ERROR_IS_MODULE_SPECIFIC( err ) ((err) ? (err)->specific : 0 )
/* Modules */
#define eMod_Unknown "unknown"
/* General(universal) errors */
#define eErr_None 0
#define eErr_NoMem 1
-------- yarm.h ----------
enum
{
eErr_CantCreateEvent,
eErr_CantOpenRegKey,
eErr_RequestRegNotifyChangeFail,
eErr_CouldNotCreateThread,
eErr_RegQueryInfoKeyFail,
};
#define UUID_Yarm "{DACA91AC-EE0C-4e0c-93EC-2332AA21BD0A}"
these:
1) Debugging and diagnostic aid
2) User feedback
One method that is used a fair amount it to 'say' that all functions must
return an error code of a standard type, for example tError. Where tError is
typedefed as a long int. A list of error codes may then be defined in a
global header file, or perhaps upper bits of tError may indicate a module
code, and lower bits a module specific error code.
Example:
tError OpenResource( ... )
{
...
return MAKE_ERROR( MOD_RESOURCE, RESOURCE_INVALID_PATH );
}
Here MAKE_ERROR fuses the error information together to form the error
return code of type tError. Unfortunately there is no room for additional
debugging information, such as __FILE__, or __LINE__ which could be very
useful, so this method fails feature (1) somewhat.
There are other ways that I don't favour e.g: Set a global error code.
either
like C's errno. or using a GetError() / SetError() approach. And there is
setjmp and longjump.
Here is a proposed method, which seems somewhat unwieldy too ( an
abomination really ). It does have some advantages though, namely:
1) Could work with threads
2) Provides line and file number, as well as any other desirable information
to be added to the 'error' structure.
On the down side:
1) It's a bit of a mess
2) Wouldn't work in environments where global variables aren't allowed.
What I was trying to do here is a universal ( well across a single large
project ) error handling mechanism and debugging information to go with
that, namely file and line numbers. Perhaps someone can suggest a good
alternative method to yield these things. Using int return codes to API
functions, and a macro to set fields in a global structure might be more
sensible, but would fall apart in the presence of multi threading.
NB- The UUID is there so that a new set of error codes can be defined
without recompiling any core code.
--------- error.h --------
struct sError
{
char *uuid;
char *name;
int code;
int specific;
char *file;
long line;
} Error;
typedef struct sError *tError;
static tError MakeError( tError mod, int code, int specific, char *file,
long line )
{
mod->code = code;
mod->specific = specific;
mod->file = file;
mod->line = line;
return mod;
}
/* Declare a struct in the C file to hold the error information */
#define ERROR_DECALRE_MOD( mod, uuid, name ) static struct sError mod = {
uuid, name }
/* Set the error information and return a pointer to it - use like this:
return ERROR_GENERAL( ParserModule, eParse_BadlyFormedConstant );
*/
#define ERROR_SPECIFIC( mod, code ) MakeError( &mod, code, 1, __FILE__,
__LINE__ )
#define ERROR_GENERAL( mod, code ) MakeError( &mod, code, 0, __FILE__,
__LINE__ )
#define ERROR_GET_CODE( err ) ((err) ? (err)->code : 0)
/* Each module has some sort of UUID so that a user interface can locate
user error messages and diplay them */
#define ERROR_GET_MOD( err ) ((err) ? (err)->uuid : eMod_Unknown)
#define ERROR_IS_MOD( err, uuid ) ((err) ? !strcmp((err->uuid), (uuid)):
0 );
#define ERROR_IS_MODULE_SPECIFIC( err ) ((err) ? (err)->specific : 0 )
/* Modules */
#define eMod_Unknown "unknown"
/* General(universal) errors */
#define eErr_None 0
#define eErr_NoMem 1
-------- yarm.h ----------
enum
{
eErr_CantCreateEvent,
eErr_CantOpenRegKey,
eErr_RequestRegNotifyChangeFail,
eErr_CouldNotCreateThread,
eErr_RegQueryInfoKeyFail,
};
#define UUID_Yarm "{DACA91AC-EE0C-4e0c-93EC-2332AA21BD0A}"