with even more experience in C you get to learn to actually look at
implementations. In the strtonum(3) case, you will spot that it
actually sets errno _and_ provides a string value [...]
Looking at the implementation this way is wrong.
If this is part of its interface contract, you don't need to look at
the implementation to discover it, because the documentation will
describe it (or, if not, the function is not suitable because its
interface contract is not documented!).
If not, then it's an accident of the implementation and nobody should
depend on it.
I just asked for a technical reasoning why not have a function that
is used in several places in a library, and ideally in the same
library as other OS'es put it. I think that is a reasonable
question.
Yes. And it's been answered: because the interface is ill-designed.
Returning an error string is the wrong design. If the interface
contract specifies that there are only a few possible error strings,
and lists them, then a small integer with manifest constants (or an
enum, which is much the same thing with slightly different syntax) is
preferable (faster, less error-prone, more easily localizable). If
the
interface contract does not specify only a few possible error strings,
then the only possible uses for the string (in code that is not
intimately dependent on undocumented details of the implementation)
are
(1) as an "error occurred" boolean and (2) for direct reporting to
humans. (1) is better addressed with a boolean and (2) is both
unlikely to be desirable for a routine as low-level as strtonum and
difficult to localize properly.
The only third option is that the interface contract specifies the
precise semantics of the error string but they are such that a great
many strings are possible. In this case the existing implementation
does not conform.
Using long long is a wrong choice; it should either have a whole
family
of routines, one for each of the likely types (a la strtol, strtoq,
strtoul, strtouq), or it should use intmax_t.
Oh, you use strong words, given that you did not even look at the
implementation.
The implementation is irrelevant at this point. Badly designed
interfaces should be avoided, even if someone else has implemented
them
as well as can be. Looking at the implementation would be relevant
only if we had already decided we wanted to adopt the interface and
were considering adopting the implementation as well.