The main reason for using errno is to provide additional error information.
This is especially useful in situations where most (or even all) of the possible return values ββof a function are actually valid return values.
Consider the fopen() function, which returns a pointer to FILE . Each possible return value is also a valid return value, except for NULL . Therefore fopen() returns NULL on error. But then you cannot say what exactly caused the function to crash. Therefore, fopen() uses errno to indicate the exact error condition, that is, the file does not exist, or you do not have permission to read it, or the system does not have memory or something else.
You can think of errno as a global variable (which it was until threads became popular). Currently, errno usually a macro that reverses a function call that returns an error condition. But this is just a way to implement global variables depending on the flow.
errno alternatives are less convenient:
You can provide a function with a pointer to int , and the function can save its error condition there. strtod() is a good example of this technique. But this makes the API more complex and therefore less desirable. In addition, it forces the programmer to define a new int , which is annoying if you care if the function does not work.
In languages ββthat allow more than one return value (and do not contain exceptions), two values ββare usually returned: one for the actual result, and the other for the error condition. In languages ββsuch as "Go," you see the following code:
result, ok = foo(); if (ok) { // handle error denoted by "ok" }
Do not trust people who claim that errno is an βoldβ technique and therefore should be avoided. The machine you are programming is much older than errno or even C, and no one ever complained about it.