How can I detect whether strtol() did not convert a number? I tested it on the following simple case and it outputted 0. The obvious question now is how would I differentiate between a non-conversion and the conversion of 0?
long int li1;
li1 = strtol("some string with no numbers",NULL,10);
printf("li1: %ld\n",li1);
****
li1: 0
Since strtol () can legitimately return 0, LONG_MAX, or LONG_MIN ( LLONG_MAX or LLONG_MIN for strtoll ()) on both success and failure, the calling program should set errno to 0 before the call, and then determine if an error occurred by checking whether errno has a nonzero value after the call.
In your case you ask regarding a 0 return value and determining whether it is valid. As you have seen, a 0 value returned by strtol does not mean that the number read was 0 or that 0 is valid. To determine if 0 is valid, you must also look at the value errno was set do during the call (if it was set).
If endptr is not NULL, strtol () stores the address of the first invalid character in *endptr. If there were no digits at all, strtol () stores the original value of nptr in *endptr (and returns 0). In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid.
The strtoll () function works just like the strtol () function but returns a long long integer value. The strtol () function returns the result of the conversion, unless the value would underflow or overflow. If an underflow occurs, strtol () returns LONG_MIN. If an overflow occurs, strtol () returns LONG_MAX.
The strtol
declaration in stdio.h
is as follows:
long int strtol(const char *nptr, char **endptr, int base);
strtol
provides a robust error checking and validation scheme that allows you to determine whether the value returned is valid
or invalid
. Essentially, you have 3 primary tools at your disposal. (1) the value returned, (2) the value errno
is set to by the call, and (3) the addresses and contents of nptr
and endptr
provided to, and set by, strtol
. (see man 3 strtol
for complete details - the example in the man
page also provides a shorter set of conditions to check, but they have been expanded below for explanation).
In your case you ask regarding a 0
return value and determining whether it is valid. As you have seen, a 0
value returned by strtol
does not mean that the number read was 0
or that 0
is valid. To determine if 0
is valid, you must also look at the value errno
was set do during the call (if it was set). Specifically, if errno != 0
and the value returned by strtol
is 0
, then the value returned by strtol
is INVALID. (this condition will represent either invalid base
, underflow
, or overflow
with errno
equal to either EINVAL
or ERANGE
).
There is a second condition that can result in strtol
returning an INVALID 0
. The case where no digits were read within the input. When this occurs, strtol
sets the value of endptr == nptr
. Therefore, you must also check whether the pointer values are equal before concluding a 0
value was entered. (a VALID 0
can be entered with multiple 0's
in the string)
The following provides a brief example of the differing error conditions to check when evaluating the return of strtol
along with several different test conditions:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
int main (int argc, char **argv)
{
if (argc < 2) {
fprintf (stderr, "\n Error: insufficient input. Usage: %s int [int (base)]\n\n", argv[0]);
return 1;
}
const char *nptr = argv[1]; /* string to read */
char *endptr = NULL; /* pointer to additional chars */
int base = (argc > 2) ? atoi (argv[2]) : 10; /* numeric base (default 10) */
long number = 0; /* variable holding return */
/* reset errno to 0 before call */
errno = 0;
/* call to strtol assigning return to number */
number = strtol (nptr, &endptr, base );
/* output original string of characters considered */
printf ("\n string : %s\n base : %d\n endptr : %s\n\n", nptr, base, endptr);
/* test return to number and errno values */
if (nptr == endptr)
printf (" number : %lu invalid (no digits found, 0 returned)\n", number);
else if (errno == ERANGE && number == LONG_MIN)
printf (" number : %lu invalid (underflow occurred)\n", number);
else if (errno == ERANGE && number == LONG_MAX)
printf (" number : %lu invalid (overflow occurred)\n", number);
else if (errno == EINVAL) /* not in all c99 implementations - gcc OK */
printf (" number : %lu invalid (base contains unsupported value)\n", number);
else if (errno != 0 && number == 0)
printf (" number : %lu invalid (unspecified error occurred)\n", number);
else if (errno == 0 && nptr && !*endptr)
printf (" number : %lu valid (and represents all characters read)\n", number);
else if (errno == 0 && nptr && *endptr != 0)
printf (" number : %lu valid (but additional characters remain)\n", number);
printf ("\n");
return 0;
}
output:
$ ./bin/s2lv 578231
string : 578231
base : 10
endptr :
number : 578231 valid (and represents all characters read)
$ ./bin/s2lv 578231_w_additional_chars
string : 578231_w_additional_chars
base : 10
endptr : _w_additional_chars
number : 578231 valid (but additional characters remain)
$ ./bin/s2lv 578some2more3stuff1
string : 578some2more3stuff1
base : 10
endptr : some2more3stuff1
number : 578 valid (but additional characters remain)
$ ./bin/s2lv 00000000000000000
string : 00000000000000000
base : 10
endptr :
number : 0 valid (and represents all characters read)
$ ./bin/s2lv stuff578231
string : stuff578231
base : 10
endptr : stuff578231
number : 0 invalid (no digits found, 0 returned)
$ ./bin/s2lv 00000000000000000 -2
string : 00000000000000000
base : -2
endptr : (null)
number : 0 invalid (base contains unsupported value)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With