Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error checking a function that returns an int

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

char *foo(void) {
  //If stuff doesn't go okay
  return NULL;
}

char *bar = foo();
if(!bar) return 1;

This works great because I know in such cases that I will never intend to return NULL.

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

A couple of workarounds:

  1. Include an error code parameter in the function
  2. Return an error code and include an int pointer as a parameter

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

Is there another solution that doesn't involve changing the interface to the function? What is the most common way of dealing with this situation?

CHOSEN SOLUTION

Thank you for all your thoughts and answers on this.

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

I chose this root because generally I found that when returning more complex forms of data, the number of potential errors were almost always greater than 1. This meant that using NULL as the only source of error data was impractical anyway as it meant there was no way to determine what the error actually was. With functions returning data as an int, it also became impossible to distinguish multiple different error codes from valid data.

The same is not true, of course, for functions that aren't really returning any data in which case I am free to 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.

like image 318
Rupert Madden-Abbott Avatar asked Jan 23 '11 20:01

Rupert Madden-Abbott


People also ask

What is error Checking in C?

Global Variable errno: When a function is called in C, a variable named as errno is automatically assigned a code (value) which can be used to identify the type of error that has been encountered. Its a global variable indicating the error occurred during any function call and defined in the header file errno. h.

How to print error string in C?

Your program can use the strerror() and perror() functions to print the value of errno. The strerror() function returns a pointer to an error message string that is associated with errno. The perror() function prints a message to stderr.

How to handle exceptions in C?

The C programming language does not support exception handling nor error handling. It is an additional feature offered by C. In spite of the absence of this feature, there are certain ways to implement error handling in C. Generally, in case of an error, most of the functions either return a null value or -1.

How to make error messages in C?

The C programming language provides perror() and strerror() functions which can be used to display the text message associated with errno. The perror() function displays the string you pass to it, followed by a colon, a space, and then the textual representation of the current errno value.


3 Answers

There's the horrid solution of a global variable - analogous to errno. Not recommended.

You might use a function to retrieve the error condition from the last call to one of the functions in your set - again, not recommended. This is not thread-safe, and it is likely that you'd share errors across functions - rather than being able to interrogate for the last error from the function you used (though that could be fixed by an appropriate design).

You might decide that all your functions return a status which is testable, and the value is returned via a pointer argument. This gives you consistency across all functions, with a change in the usage pattern. You would consistently write:

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

This is probably the least obnoxious solution.

The other main alternative, of passing a pointer to an error structure or pointer to a pointer to an error structure is apt to lead to resource management issues. It can be made to work if the error structure is a fixed size so that 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 test the error condition in the same line as the function is called, which some would regard as a nuisance. It matters most when you're in the third 'else if' clause of a sequence of operations - then you have to introduce a new level of nesting where the error code as return value does not require that. In its favour, the information in the error structure can be more comprehensive than a single error number which might lead to better diagnostics.

You could use a hybrid solution - an error return code plus an error parameter to contain the extra information for improved diagnostics. It is seldom chosen, though, AFAIK.

like image 85
Jonathan Leffler Avatar answered Nov 03 '22 01:11

Jonathan Leffler


You could just sacrifice the largest negative or positive number for an int such as INT_MAX. Just make a const MY_INT_ERROR_VALUE and compare to it.

like image 44
stefan Avatar answered Nov 03 '22 02:11

stefan


There are several ways to do what you want, but all of them will make you have a non-homogeneous interface (or at list a non-homogeneous way to test for errors).

If you can't change the signature of your function you could use a global variable that your function sets when an error happens, but I think this solution would be dirtier than changing the interface.

Yet another solution could be that of simulating exceptions using a jump or a system signal, but still I wouldn't suggest this (this is also not portable).

like image 27
peoro Avatar answered Nov 03 '22 01:11

peoro