3

Even though the string conversion succeeds, testing errnoreturns a value indicating an error:

#include <stdlib.h>
#include <sys/errno.h>

const char* numberString = "7";
char* endPtr;
errno = 0;
long number = strtol(numberString, &endPtr, 10);
NSLog(@"%ld", number);
if (errno) {
    perror("string to integer conversion failed");
}

The output is (on the Simulator, iOS 7)

$ 2014-05-22 09:27:32.954 Test[2144:60b] 7
$ string to integer conversion failed: No such process

The behavior is similar on the device.

The man page for strtol says in a comment:

RETURN VALUES
The strtol(), strtoll(), strtoimax(), and strtoq() functions return the result of the conversion, unless the value would underflow or overflow. If no conversion could be performed, 0 is returned and the global variable errno is set to EINVAL (the last feature is not portable across all platforms). If an overflow or underflow occurs, errno is set to ERANGE and the function return value is clamped according to the following table.

It's quite unclear what this exactly means for iOS. Any insights here?

Edit:

It turned out that the function call NSLog did set errno. So, @Mat in his answer and comments was spot on, saying that "all bets are off when testing errno AFTER calling an unrelated function (here NSLog).

CouchDeveloper
  • 18,174
  • 3
  • 45
  • 67
  • 1
    It looks like `errno` is only set if `strtol` fails - since `strtol` succeeds then you should not be trying to read `errno`. – Paul R May 22 '14 at 07:47

1 Answers1

4

If no conversion could be performed, 0 is returned

You're not in that case, 7 was returned.

If an overflow or underflow occurs, ... the return value is clamped according to the following table.

You're not in that case either.

So strtol didn't fail. Inspecting errno is meaningless. Function that are documented to set errno on failure will do so, in case of failure. When no failure happened, the value of errno is "morally" undefined. Don't inspect it.

strtol is a special case though. POSIX requires the following:

These functions shall not change the setting of errno if successful.

So your example should be ok. Except that you're calling a function between the strtol call and your inspection of errno. If you're 100% sure that that function will not itself change errno, or call another function that might set it, then you'd be ok in this very specific case (a function documented not to alter errno in case of success - this is not the norm). Apparently that's not the case though. NSLog will very likely use some system calls at some point, and those (in general) have no guarantee of not altering errno.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • That makes sense. By the way, there is an example at cppreference.com which seems to be incorrect much like my sample: [strtol example](http://en.cppreference.com/w/c/string/byte/strtol) – CouchDeveloper May 22 '14 at 07:55
  • Hum. Strange, that's usually an excellent reference. Let me check if I didn't miss something here. – Mat May 22 '14 at 07:58
  • 1
    @CouchDeveloper: yep, sorry, my answer wasn't actually correct. I believe it is now though, and the "general advice" does apply - don't test errno in case of success, and check errno _immediately_ after the call that failed. That example in cppreference needs to reset errno to zero just before the strol call in the loop to be valid, unless I'm missing something else :-/ – Mat May 22 '14 at 08:12
  • Thanks for the update. Please notice that I too set `errno` to zero _before_ calling `strtol`. And despite `strtol` shouldn't touch `errno` since it succeeds, it returns `ESRCH` ("No such process"). `ESRCH` is even not listed as one of the possible error codes for `strtol` in the man page. – CouchDeveloper May 22 '14 at 08:56
  • @CouchDeveloper: you're calling a function between `strtol` and your check of errno. All bets are off. – Mat May 22 '14 at 08:57
  • Mat, you were absolutely correct! The function `NSLog` actually set errno! Strange, but this is how it is. Thanks for helping. :) – CouchDeveloper May 22 '14 at 09:01