Reputation: 993
In all of the examples for Error handling in C and several answers on SO, all programs just exit with a status code. I'm not looking for any of that.
Error is part of input and output and a routine can either return result or fault. I want the function to return with proper details of error instead of just abnormal exit or result in case of success.
Following is not a working but I'm looking for something similar, to indicate both result or error in return of the function.
struct Error {
int code;
char *message;
};
int div(int x, int y) {
if( y == 0){
struct Error *error = {0, "Division by zero!"};
return error;
} else {
return x / y;
}
}
int main() {
printf("%d", div(4, 2));
printf("%d", div(4, 0));
}
Upvotes: 3
Views: 305
Reputation: 822
For all its flaws, Zed Shaw's 'learn C the hard way' has a nice section on "The C Error Handling Problem" that you may find interesting.
I think one way to tackle this problem is to use debug macros to wrap the global 'errno' value that C provides.
The below 'dbg.h' code is taken from Zed Shaw's book:
dbg.h:
#ifndef __dbg_h__
#define __dbg_h__
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef NDEBUG
#define debug(M, ...)
#else
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n",\
__FILE__, __LINE__, ##__VA_ARGS__)
#endif
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
#define log_err(M, ...) fprintf(stderr,\
"[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__,\
clean_errno(), ##__VA_ARGS__)
#define log_warn(M, ...) fprintf(stderr,\
"[WARN] (%s:%d: errno: %s) " M "\n",\
__FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n",\
__FILE__, __LINE__, ##__VA_ARGS__)
#define check(A, M, ...) if(!(A)) {\
log_err(M, ##__VA_ARGS__); errno=0; goto error; }
#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\
errno=0; goto error; }
#define check_mem(A) check((A), "Out of memory.")
#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\
errno=0; goto error; }
#endif
In your code that you want to check you could then do something like:
#include <stdio.h>
#include "dbg.h"
int div(int x, int y) {
check ( y != 0, "Division by zero!");
return x / y;
error:
log_err("Div by zero error.");
return 0;
}
int main() {
printf("%d", div(4, 2));
printf("%d", div(4, 0));
}
This way your error is caught and handled by the code in 'dbg.h'. Now this has one obvious problem in that when div(x, 0) is called: div returns 0. The problem is div() has to return an int and all ints can be produced by some valid combination of div(x, y) for ints x and y.
One solution is to wrap div in another function:
#include <stdio.h>
#include <stdlib.h>
#include "dbg.h"
char *div_interface(int x, int y) {
check ( y != 0, "Division by zero!");
char *buffer = malloc(100);
sprintf(buffer, "%d", (x / y));
return buffer;
error:
log_err("Div by zero error.");
char *err_ret= strdup("Div by zero error.");
return err_ret;
}
int main() {
char *div_1 = div_interface(4, 2);
printf("%s\n", div_1);
free(div_1);
char *div_2 = div_interface(4, 0);
printf("%s\n", div_2);
free(div_2);
}
This isn't particularly elegant either though! The caller would then have to do the conversion from char* to an int...
Upvotes: 1
Reputation: 602
You can't return structure while function is returning int. But you can return different integers and then handle it something like that.
typedef struct Error {
int code;
char message[512];
};
int div(int x, int y, Error *err) {
if( y == 0) {
err->code = 0;
strcpy(err->message, "Division by zero!");
return -1;
} else {
return x / y;
}
}
int main() {
Error err;
int retValue = div(4, 2, &err);
if (retValue < 0)
{
printf("Code: %d, Message: %s\n", err->code, err->message);
}
else
{
printf("%d\n", retValue);
}
}
I know that sometimes result may be less than zero but its but it's just a rough example.
Upvotes: 0
Reputation: 213799
struct Error *error =
-> struct Error error =
, then make your return type struct Error
.
But since you have a struct, returning by value isn't usually a good idea. Furthermore, the return value of a mathematical function is likely expected to be the mathematical result. Therefore a better approach than returning an error, would be to use an optional parameter:
#include <stdio.h>
#include <stdlib.h>
typedef enum
{
ERR_NONE,
ERR_DIV_BY_ZERO
} err_code_t;
typedef struct
{
err_code_t code;
const char *message;
} err_t;
int division (int x, int y, err_t* err)
{
int result;
if( y == 0)
{
if(err != NULL)
{
err->code = ERR_DIV_BY_ZERO;
err->message = "Division by zero";
}
result = 0;
}
else
{
result = x / y;
}
return result;
}
void error_handler (const err_t* err)
{
fprintf(stderr, "Error %d: %s", err->code, err->message);
exit(EXIT_FAILURE);
}
int main()
{
err_t err;
int result;
result = division(4, 2, NULL); // NULL meaning don't give any error information
printf("%d\n", result);
result = division(4, 0, &err);
if(err.code != ERR_NONE)
{
error_handler(&err);
}
printf("%d\n", result);
}
Upvotes: 4