Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting strtol failure [duplicate]

Tags:

c

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
like image 290
Apollo Avatar asked Sep 28 '14 01:09

Apollo


People also ask

How to check if strtol () is working or not?

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.

How to determine if a strtol return value is valid?

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).

What does strtol () do in C++?

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.

What is the difference between strtoll () and strtol ()?

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.


Video Answer


1 Answers

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)
like image 69
David C. Rankin Avatar answered Oct 24 '22 01:10

David C. Rankin