This isn't the usual way this is coded:<p><pre><code> char *one = "one";
char *end;
errno = 0; // remember errno?
long i = strtol(one, &end, 10);
if (errno != 0) {
perror("Error parsing integer from string: ");
} else if (i == 0 && end == one) {
fprintf(stderr, "Error: invalid input: %s\n", one);
} else if (i == 0 && *end != '\0') {
f__kMeGently(with_a_chainsaw);
}
</code></pre>
It's actually like this:<p><pre><code> errno = 0;
long i = strtol(input, &end, 10);
if (end == input) {
// no digits were found
} else if (*end != 0 && no_ignore_trailing_junk) {
// unwanted trailing junk
} else if ((i == LONG_MIN || i == LONG_MAX)) && errno != 0) {
// overflow case
} else {
// good!
}
</code></pre>
errno only needs to be checked in the LONG_MIN or LONG_MAX case. These cares are ambiguous: LONG_MIN and LONG_MAX are valid values of type long, and they are used for reporting an underflow or overflow. Therefore errno is reset to zero first. Otherwise what if errno contains a nonzero value, and LONG_MAX happens to be a valid, non-overflowing value out of the function?<p>Anyway, you cannot get away from handling these cases no matter how you implement integer scanning; they are inherent to the problem.<p>It's not strtol's fault that the string could be empty, or that it could have a valid number followed by junk.<p>Overflows stem from the use of a fixed-width integer. But even if you use bignums, and parse them from a stream (e.g. network), you may need to set a cutoff: what if a malicious user feeds you an endless stream of digits?<p>The bit with errno is a bit silly; given that the function's has enough parameters that it could have been dispensed with. We could write a function which is invoked exactly like strtoul, but which, in the overflow case, sets the *end pointer to NULL:<p><pre><code> // no assignment to errno before strtol
int i = my_strtoul(input, &end, 10);
if (end == 0) {
// underflow or overflow, indicated by LONG_MIN or LONG_MAX value
} else if (end == input) {
// no digits were found
} else if (*end != 0 && no_ignore_trailing_junk) {
// unwanted trailing junk, but i is good
} else {
// no trailing junk, value in i
}
</code></pre>
errno is a pig; under multiple threads, it has to access a thread local value. E.g<p><pre><code> #define errno (*__thread_specific_errno_location())
</code></pre>
The designer of strtoul didn't do this likely because of the overriding requirement that the <i>end</i> pointer is advanced past whatever the function was able to recognize as a number, no matter what. This is lets the programmer write a tokenizer which can diagnose the overflow error, and then keep going with the next token.