Error checking function that returns int

If I have a function that returns some kind of pointer, I check for errors by setting the error to return NULL on error.

char *foo(void) { //If stuff doesn't go okay return NULL; } char *bar = foo(); if(!bar) return 1; 

This works fine because I know in such cases that I'm never going to return NULL.

However, sometimes I will have functions that return integers (in this case, I read ints from the configuration file). However, the problem is that now there is no way to check the return value for errors, because any value (including 0) can be genuine.

A few workarounds:

  • Include error code parameter in function
  • Returns an error code and includes an int pointer as a parameter

The problem with both of them is that I have a set of functions that all do the same thing, but for different types, and I want to support a normal interface so that they can be used the same way.

Is there any other solution that is not related to changing the interface to the function? What is the most common way to deal with this situation?

SELECTION OF DECISION

Thanks for all your thoughts and answers to this.

In the end, I decided that if the function is designed to return some data, the error can only be returned through the error parameter. Otherwise, the error is returned directly.

I chose this root because, as a rule, I found that when returning more complex data forms, the number of potential errors was almost always greater than 1. This meant that using NULL as the sole source of error data was impractical, as it did not mean no way to determine what was actually a mistake. With functions returning data as int, it has also become impossible to distinguish several different error codes from valid data.

The same is not true, of course, for functions that do not actually return any data, in which case I can use the return value as an error code.

I also like the fact that the above pattern makes a clear distinction between functions that return data and functions that don't.

+6
c error-handling
source share
7 answers

Here is a terrible solution to a global variable - similar to errno . Not recommended.

You can use the function to get the error condition from the last call to one of the functions of your set - again, not recommended. This is not thread safe, and it is likely that you will share errors between functions, and you will not be able to poll the latest error from the function you are using (although this can be fixed using the appropriate design).

You can decide that all of your functions return a status that can be checked, and the value is returned through a pointer argument. This gives you consistency in all functions with a change in usage pattern. You will write in sequence:

 if ((rc = your_function(in1, in2, &out)) != 0) ...handle error... else ...use returned value... 

This is probably the least unpleasant decision.

Another major alternative, which is passing a pointer to an error structure or a pointer to a pointer to an error structure, can lead to resource management problems. It can be made to work if the error structure is a fixed size, so the resource management problem goes away.

 Error_t err; int result = your_function(in1, in2, &err); if (err.code != 0) ...handle error... else ...use returned value... 

You cannot check the error condition on the same line as the function, which some consider inconvenience. This is most important when you are in the third section of the "else if" sequence of operations - then you need to enter a new level of nesting, where the error code as the return value does not require this. In turn, the information in the error structure can be more complete than one number of errors, which can lead to better diagnostics.

You can use a hybrid solution - an error return code plus an error parameter to contain additional information to improve diagnostics. He is rarely chosen, AFAIK.

+4
source share

The best and most common way (for example, the Windows API used) is to write all error handling as follows:

int func (error Error_t *);

where Error_t is a kind of error indication. Thus, this will not interfere with the returned result.

+3
source share

You can simply sacrifice the largest negative or positive number for int, for example INT_MAX. Just do const MY_INT_ERROR_VALUE and compare with it.

+2
source share

There are several ways to do what you want, but all of them will force you to have a heterogeneous interface (or a list is an uneven way to check for errors).

If you cannot change the signature of your function, you can use the global variable that your function sets when an error occurs, but I think this solution would be messier than changing the interface.

Another solution might be to model exceptions using a jump or a system signal, but still I would not suggest this (this is also not portable).

+1
source share

How about this:

 void *foo(void *res) { // cast the void *res to whatever type the result would be if (/* successfull */) return res; /* error */ return NULL; } 

Thus, you will have the same signature for all these functions, and you can easily check for errors.

+1
source share

My preference when writing code in a language that lacks exception handling should always use the return value as an error indicator.

 int get_value(int *value) { if ( input_ok ) *value = input; return 0; return -1; } 

this does not seem practical, as it forces you to use intermediate variables to store the results of the function, but it has been very useful to catch errors and handle them correctly (you can never rely on user input).

it should also be noted that having a special meaning to show an error is not a good idea: you never know what will happen to your code. if later you want to add a new function, and, unfortunately, a special value is useful for this function, what will you do? write a new function with another special error value? What if the input signal should cover the entire range of the return type? if it is part of a larger project, how can you make sure that every programmer who can use your function knows about a special meaning?

so err is on the safe side: do not use a special value and use a special error handling path.

note that you can cancel the above code and write int get_value(int *error);

0
source share

1. Use NaN, for example, floating coprocessors. Choose a value that can never be used as a result to indicate an error.

 # define VALUE_OF_FAIL (-99999) 

So then:

 char foo(void) { // If stuff doesn't go okay return VALUE_OF_FAIL; } char bar = foo(); if (bar == VALUE_OF_FAIL) return 1; 

Again, you must ensure that the result of regular calculation is never VALUE_OF_FAIL. Select a number from the periphery of the integer range. You can define more fault codes, but then you should write a function that checks the variable for failure.

2. Organize your compute code for the class, then add the isValid () method:

 class FooBar { public FooBar() { // constructor this.fail = false; // initialize here... } char foo(void) { // the computation method this.fail = false; // ...or here // If stuff doesn't go okay this.fail = true; // or error code return 0; // any value } bool failed() { return this.fail; } } // outside the class fb = new FooBar(); char bar = fb->foo(); if (fb->failed()) return 1; 
-one
source share

All Articles