9

The C standard mandates that no C standard library functions shall set errno to zero. Why exactly is this?

I could understand it being useful for calling several functions, and only checking errno after the last one - for example:

errno = 0;
double x = strtod(str1, NULL);
long y = strtol(str2, NULL);
if (errno)
    // either "strtod" or "strtol" failed
else
    // both succeeded

However, is this not considered "bad practice"? Since you're only checking errno at the very end, you only know that one of the functions did fail, but not which function failed. Is simply knowing that something failed good enough for most practical programs?

I tried looking for various C Rationale documents, but many of them don't have much detail for <errno.h>.

migrated from stackoverflow.com Aug 28 '13 at 13:45

This question came from our site for professional and enthusiast programmers.

  • 1
    I guess it's "don't pay for what you don't want". If you care about errno, you can always set it to zero yourself. – Kerrek SB Aug 7 '13 at 21:16
  • 2
    Something else to be aware of is that a function can set errno to a non-zero value even if it succeeds. (It might call some other function that fails, but that doesn't constitute a failure in the outer function.) – Keith Thompson Aug 7 '13 at 22:38
10

The C library does not set errno to 0 for historical reasons1. POSIX no longer claims its libraries will not alter the value in case of success, and the new Linux man page for errno.h reflects this:

The <errno.h> header file defines the integer variable errno, which is set by system calls and some library functions in the event of an error to indicate what went wrong. Its value is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno.

The ANSI C Rationale states that the committee felt it was more practical to adopt and standardize the existing practice of using errno.

The error reporting machinery centered about the setting of errno is generally regarded with tolerance at best. It requires a ``pathological coupling'' between library functions and makes use of a static writable memory cell, which interferes with the construction of shareable libraries. Nevertheless, the Committee preferred to standardize this existing, however deficient, machinery rather than invent something more ambitious.

There is almost always a way to check for error outside of checking if errno got set. Checking if errno got set is not always reliable, since some calls require calling a separate API to get the error reason. For instance, ferror() is used to check for an error if you get a short result from fread() or fwrite().

Interestingly enough, your example of using strtod() is one of the cases where setting errno to 0 before the call is required to correctly detect if an error has occurred. All the strto*() string to number functions have this requirement, because a valid return value is returned even in the face of an error.

errno = 0;
char *endptr;
double x = strtod(str1, &endptr);
if (endptr == str1) {
    /*...parse error */
} else if (errno == ERANGE) {
    if (x == 0) {
        /*...underflow */
    } else if (x == HUGE_VAL) {
        /*...positive overflow */
    } else if (x == -HUGE_VAL) {
        /*...negative overflow */
    } else {
        /*...unknown range error? */
    }
}

The above code is based on the behavior of strtod() as documented on Linux. The C standard only stipulates that underflow cannot return a value greater than the smallest positive double, and whether or not errno is set to ERANGE is implementation defined2.

There is actually an extensive cert advisory write-up that recommends always setting errno to 0 before a library call and checking its value after the call indicates a failure has occurred. This is because some library calls will set errno even if the call itself was successful3.

The value of errno is 0 at program startup, but it is never set to 0 by any library function. The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in the C Standard. It is meaningful for a program to inspect the contents of errno only after an error has been reported. More precisely, errno is meaningful only after a library function that sets errno on error has returned an error code.


1. Previously I claimed it was to avoid masking an error from an earlier call. I can't find any evidence to support this claim. I also had a bogus printf() example.
2. Thanks to @chux for pointing this out. Reference is C.11 §7.22.1.3 ¶10.
3. Pointed out by @KeithThompson in a comment.

  • Minor issue: it appears underflow could result in a non-0 result: "the functions return a value whose magnitude is no greater than the smallest normalized positive number in the return type" C11 7.22.1.3.10. – chux Aug 8 '13 at 0:00
  • @chux: Thanks. I'll make an edit. Since setting errno to ERANGE is implementation defined in the case of underflow, there is actually no portable way to detect underflow. My code followed what I found in the Linux man page on my system. – jxh Aug 8 '13 at 0:09
  • Your comments about the strto* functions is exactly why I asked if my example would be considered bad practice, but it's the only way in which errno not being set to zero would be useful, or even apply. – Drew McGowen Aug 8 '13 at 2:40
  • @DrewMcGowen: I guess the only point you can take is that errno may get set even in the case of success, so just using the fact it got set is not really a good enough indicator that an error occurred. You have to check the results of the individual calls themselves to know if an error happened at all. – jxh Aug 8 '13 at 3:08
1

You can do error check for both of the function call, if you really care about.

errno = 0;
double x = strtod(str1, NULL);
if (errno)
    // strtod"  failed
else
    // "strtod" succeeded

long y = strtol(str2, NULL);
if (errno)
    // "strtol" failed
else
    // "strtol" succeeded

Since we never know how mach function called in a process , how can the lib set errnos for each function call, Right?

1

Arbitrarily changing the errorno is analogous to 'catching and swallowing' an exception. Before there were exceptions that would propagate through different layers of a program and finally reach a point where the caller will either catch and respond to the exception in some way or simple pass the buck, there were errnos. Not altering the errno, unless you are somehow handling, overriding, treating as irrelevant, the error, is essential to this first generation error handling propagation paradigm.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.