You might want to familiarize yourself with how errno works.
It is not used for reporting. Rather, various functions in C and POSIX return an indication that some exceptional situation has occurred. Then errno holds a value which classifies the cause of that situation. It doesn't report the error.
(In the case of portable ISO C, we can't even depend on that; we must set errno to zero before calling most library functions. If that function fails, then if errno is nonzero, it has a value pertaining to that function.)
Some newer functions in POSIX return the errno value, like pthread_mutex_lock. That makes sense when the return value has no other purpose like "bytes processed" or whatever. The errno values are positive, so they combine poorly with in-band signaling.
Anyway, optimizing is possible based on the return value: like putting the expected success case into the hot code path or whatever.
Thank you, I'm aware how errno works. C has been able to return structs for the last 30 years, so returning a pair of value+error code is no big issue even in C.
Optimizing errno is so easy that many compilers by default do not even update errno for many math functions because it hopelessly destroy any chance of vectorizing and aggressive optimizations.
To be fair, the issue of ergonomics is an artifact of C only. In a language with proper sum types (or as I like to think of them, "better enums"), the pattern would look more like this:
yes, the syntax is not great, but it is not really worse than errno. Especially because you can initialize the error object at declaration point and, as you pointed out, you would otherwise need to zero errno:
struct error res = library_function(arg);
if (res.result)
{
// use res.errno
...
}
Also remember the whole thread is about improving the syntax for this sort of stuff. C could take (another) page from C++:
auto [result, errno] = library_function(arg);
if (result == -1)
{
// use errno ...
}
It is not used for reporting. Rather, various functions in C and POSIX return an indication that some exceptional situation has occurred. Then errno holds a value which classifies the cause of that situation. It doesn't report the error.
(In the case of portable ISO C, we can't even depend on that; we must set errno to zero before calling most library functions. If that function fails, then if errno is nonzero, it has a value pertaining to that function.)
Some newer functions in POSIX return the errno value, like pthread_mutex_lock. That makes sense when the return value has no other purpose like "bytes processed" or whatever. The errno values are positive, so they combine poorly with in-band signaling.
Anyway, optimizing is possible based on the return value: like putting the expected success case into the hot code path or whatever.