3 ms·
> conventional, consistent[1], and documented--semantics of only setting errno on error. From that man page: > The implementation may also set errno to EINVAL
by roelschroeven 1y ago
> conventional, consistent[1], and documented--semantics of only setting errno on error.
From that man page:
> The implementation may also set errno to EINVAL in case no conversion was performed (no digits seen, and 0 returned).
There are error cases where the implementation may set errno to EINVAL. There's not even a guarantee. I did a quick test. errno is only set if you pass an invalid base, or if the string does contain a number but it is out of range. If you pass a string which doesn't even remotely look like a number, errno is not set. You have to check endptr.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
const char *s = "this is not a number";
printf("strtol(\"%s\")\n", s);
errno = 0;
long a = strtol(s, NULL, 10);
printf("errno: %d; strerror: %s\n", errno, strerror(errno));
printf("result: %d\n", a);
return 0;
}
Output:
strtol("this is not a number")
errno: 0; strerror: Success
result: 0
https://godbolt.org/z/TbEKss8zM https://godbolt.org/z/TbEKss8zM
That's just rubbish design. In what is in my opinion the most common error case, namely that the string doesn't represent a number while you expect that it does, errno is not set.
- spyrja 1y agoPersonally I'd just go the wrapper approach and ignore errno entirely. #include <assert.h> #include <ctype.h> #include <limits.h> #include <stdbool.h> #include <stdint.h> #include <stdlib.h> bool copy_str_to_long_long(const char* str, long long* ptr) { while (isspace(*str)) ++str; if (*str == 0) return false; char* parsed = NULL; long long value = strtoll(str, &parsed, 0); while (isspace(*parsed)) ++parsed; if (*parsed != 0) return false; *ptr = value; return true; } long long str_to_long_long(const char* str) { long long result; assert(copy_str_to_long_long(str, &result)); return result; } bool copy_str_to_long(const char* str, long* ptr) { long long buffer; if (!copy_str_to_long_long(str, &buffer) || buffer < LONG_MIN || buffer > LONG_MAX) return false; *ptr = buffer; return true; } long str_to_long(const char* str) { long result; assert(copy_str_to_long(str, &result)); return result; } /* ...define copy_str_to_short, copy_str_to_int32, etc... */