Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why to use 'errno' at all?

Tags:

c

std

libc

I'm a CS student at the Technion, I have just learned of errno variable and c-style function calls. This makes me wonder, if c-style syscalls use registers to return a value, why should anyone use errno at all?

like image 881
David Avatar asked May 15 '11 08:05

David


People also ask

Should I set errno?

Indeed we should only check errno in the case where an error occurred. This is because if no error occurred, then it is still possible that errno will contain a non-zero value (e.g. if an error occurred during the execution of a library call but the error was recovered).

Do I need to set errno to 0?

Initializing ErrnoYour program should always initialize errno to 0 (zero) before calling a function because errno is not reset by any library functions. Check for the value of errno immediately after calling the function that you want to check. You should also initialize errno to zero after an error has occurred.

Is errno positive or negative?

The standard errno is a positive number, linux kernel uses the negative values.

Is errno always positive?

Error numbers and names Valid error numbers are all positive numbers. The <errno. h> header file defines symbolic names for each of the possible error numbers that may appear in errno. All the error names specified by POSIX.


3 Answers

The main reason for using errno is to give more information about the error condition.

This is especially useful in situations where most (or even all) possible return values of a function are actually valid return values.

Consider the fopen() function, which returns a pointer to a FILE. Every possible return value is also a valid return value, except NULL. So fopen() returns NULL on failure. But then you can't tell what exactly made the function fail. Hence, fopen() uses errno to denote the exact error condition, i.e. the file doesn't exist, or you don't have permission to read it, or the system is out of memory, or whatever.

You can think of errno as a global variable (which it used to be until threads became popular). Nowadays, errno is usually a macro wrapping a function call returning the error condition. But this is just C's way of implementing thread-specific global variables.

The alternatives to errno are less comfortable:

You could supply a function with a pointer to an int, and the function can store its error condition there. strtod() is a good example of this technique. But this makes the API more complicated and hence less desirable. Also, it forces the programmer to define a new int, which is annoying if you don't care if the function fails.

In languages that allow more than one return value (and don't feature exceptions), it's common to return two values: one for the actual result and another to denote the error condition. In languages like Go, you see code like the following:

result, ok = foo();
if (ok) {
    // handle error denoted by "ok"
}

Don't trust people who claim that errno is an "old" technique and hence to be avoided. The machine you're programming is far older than errno or even C, and nobody has ever complained about that.

like image 121
Philip Avatar answered Oct 04 '22 18:10

Philip


The design of the C library was done a long time ago at the same time as early Unix. Use of a separate error code is not an uncommon pattern (Win32 has the similar GetLastError()). And it has superficial advantages.

If you decide you want a class of functions to have a return value that is commonly used, then you can't easily use that to return errors. For example, imagine a hypothetical API

mytime_t t = get_current_time();

The common use of this API is to get time. But perhaps it can fail in some circumstances, and you get detailed error information from errno. This makes the API code a bit easier to read and write than if you had to say

mytime_t t=0;
errno_t e = get_current_time(&t);

So superficially, errno-type systems are appealing. However, the separation of error state from the actual function call leads to lots of problems. Modern environments make errno_t a per-thread variable (removing the most obvious source of problems), but you still face the problem that if you do

mytime_t t = get_current_time();
mysize_t s = get_window_size();

then you destroy the errno from the first function invisibly. This gets even more complex when code can run in error paths or where one function is implemented in terms of others. Lots of saving and restoring errno values ensures. I think it's pretty well accepted now that such systems are fragile and undesirable.

Many folks use exceptions which carry errors outside the explicit parameter/return set (many C++ programmers make this choice). Folks working in exception-free languages or environments tend to bite the bullet and reserve the return value for an error and always provide output through parameters (COM makes this choice with HRESULTs).

like image 43
Martyn Lovell Avatar answered Oct 04 '22 18:10

Martyn Lovell


errno is a complicated thing, in that it is an historic interface that probably nowadays nobody would design like that. In addition on most systems it nowadays only looks like a variable, it ain't one. Usually it is implemented as a macro that hides a function call, and that function call returns a thread specific error condition.

like image 45
Jens Gustedt Avatar answered Oct 04 '22 19:10

Jens Gustedt