Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ways to avoid/lessen the pain of the return value check after every single function call?

In languages and/or libraries which do not support exceptions, many/almost all functions return a value indicating success or failure of their operation - the best-known example being perhaps UN*X system calls such as open() or chdir(), or some libc functions.

Anyway, when I write C code, it very often ends up looking like this:

int retval;
...
retval = my_function(arg1, arg2);
if (retval != SUCCESS_VALUE) { do_something(); }

retval = my_other_function(arg1, arg2);
if (retval != SUCCESS_VALUE) { do_something_else(); }

Now, what I would like is to just not save the retval anywhere and have errors thrown in exceptions, but I can't have that. What's the next best thing? I know that there's no real solution to this problem, but I would still like to do something.

Some ideas:

  • Try to live with assert()'s (but that's not for production code which can't afford to just die).
  • Wrap function calls with a macro or a return-value-checking function, e.g. ensure_success(my_function(args) or ensure_success(my_other_function(args),my_error_handler,error_handler_args).

Is there any other practice in this matter I might prefer?

Edit:

  • Yes, I'm writing C code. I respect your opinion that I should try to avoid writing in C altogether, but that's really not constructive. This is not a language-wars question, please don't make it one.
  • I'm not asking for opinions on what is the best thing to do, I just want additional possibilities. (I'll pick one I like, other people might pick something else.)
like image 442
einpoklum Avatar asked Jun 27 '13 11:06

einpoklum


People also ask

What does a function return when no return is specified inside the function?

If no return statement appears in a function definition, control automatically returns to the calling function after the last statement of the called function is executed. In this case, the return value of the called function is undefined.

How do you return and pass data from one function to another in Javascript?

If the return value of a function is only going to be used as an input parameter of another function, you can pass the return value directly to the function parameter. This is done by putting the function call in the parameters list of the other function call, just like you would a variable.


2 Answers

Try to approach this problem with a sort of scientific curiosity. There are many that claim that C's approach to error handling leads to programmers being more aware of error conditions, paying more attention to errors and where/how they should be treated. Just consider this an exercise (if a bit tedious) of awareness, like meditation :)

Don't fight it. Solve this as much as possible in the spirit of C and your view of things will expand slightly.

Check out this article on C error handling mantra: http://tratt.net/laurie/tech_articles/articles/how_can_c_programs_be_so_reliable

One general answer to your general question is: try to make functions as small as possible so that you can directly return from them on errors. This approach is good in all languages. The rest is an exercise in structuring code.

like image 100
ctn Avatar answered Nov 08 '22 09:11

ctn


There are many ways to achieve better error handling. It all depends on what you are trying to do. To implement extensive error handling routines just to call a few functions isn't going to be worth the fuss. In larger code bases, you can consider it.

Better error handling is most often achieved by adding more abstraction layers. For example, if you have these functions

int func1 (int arg1, int arg2)
{
  return arg1 == arg2;
}

int func12 (int arg1, int arg2)
{
  return arg1 - arg2;
}

and some error handler function:

void err_handler_func1 (int err_code)
{
  if(err_code != 0)
  {
    halt_and_catch_fire();
  }
}

then you could group functions and error handlers together. Either by making a struct based data type containing one function and one error handler, and then make an array of such structs. Or by making individual, related arrays accessed with an index:

typedef void(*func_t)(int, int);
typedef void(*err_handler_t)(int);

typedef enum
{
  FUNC1,
  FUNC2,
  ...
  FUNC_N // not a function name, but the number of items in the enum
} func_name_t;

const func_t function [FUNC_N] =
{
  func1,
  func2,
  ...
};

const err_handler_t err_handler [FUNC_N] = 
{
  err_handler_func,
  err_handler_func,
  ...
}

once you have this, you can make wrap the function calls in a suitable abstraction layer:

void execute_function (int func_n, int arg1, int arg2)
{
  err_handler[func_n]( function[func_n](arg1, arg2 );
}

execute_function (FUNC1, 1, 2);
execute_function (FUNC2, 2, 2);

and so on.

like image 40
Lundin Avatar answered Nov 08 '22 07:11

Lundin