2014-09-28 13 views
5

Jak wykryć, czy strtol() nie dokonał konwersji liczby? Przetestowałem to na następującym prostym przykładzie, a wynik wyniósł 0. Teraz oczywistym pytaniem jest, w jaki sposób powinienem rozróżnić pomiędzy brakiem konwersji a konwersją 0?Wykrywanie błędu strtol

long int li1; 
li1 = strtol("some string with no numbers",NULL,10); 
printf("li1: %ld\n",li1); 

**** 
li1: 0 
+2

[C++ - prawidłowe użycie strtol] (http: // StackOverflow. com/questions/14176123/correct-usage-of-strtol) – DOOM

Odpowiedz

15

Deklaracja strtol w stdio.h jest następujący:

long int strtol(const char *nptr, char **endptr, int base); 

strtol zapewnia niezawodne sprawdzanie błędów i walidacji systemu, który pozwala na określenie, czy wartość zwracana jest valid lub invalid. Zasadniczo masz do dyspozycji 3 podstawowe narzędzia. (1) wartość powrócił (2) wartość errno jest ustawiony przez wywołanie i (3) adresy i zawartość nptr i endptr dostarczone i ustala, strtol. (Aby uzyskać szczegółowe informacje, patrz: man 3 strtol - przykład na stronie man zapewnia także krótszy zestaw warunków do sprawdzenia, ale zostały one rozwinięte poniżej w celu wyjaśnienia).

W twoim przypadku pytasz o wartość zwracaną 0 i określasz, czy jest ona ważna. Jak widzisz, wartość 0 zwrócona przez strtol wynosi , a nie oznacza, że ​​odczytana liczba to 0 lub że 0 jest poprawna. Aby ustalić, czy kod 0 jest prawidłowy, należy również sprawdzić, czy podczas połączenia ustawiono wartość errno (jeśli została ustawiona). W szczególności, jeśli errno != 0 i wartość zwrócona przez strtol wynosi 0, wówczas wartość zwrócona przez strtol wynosi INVALID. (warunek ten będzie oznaczać invalid base, lub overflow z errno równy albo EINVAL lub ERANGE).

Istnieje drugi warunek, który może spowodować, że strtol zwróci INVALID0. Przypadek, w którym nie podano cyfr w obrębie wejścia. Gdy to nastąpi, strtol ustawia wartość endptr == nptr. Dlatego należy również sprawdzić, czy wartości wskaźników są równe przed wprowadzeniem wartości 0. (A WAŻNA0 mogą być wprowadzone z wielu 0's w ciągu)

Poniżej przedstawiono krótki przykład zróżnicowanych warunkach błędach, by sprawdzić podczas oceny zwrotu strtol wraz z kilku różnych warunkach testowych:

#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; 
} 

Wydajność:

$ ./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) 
Powiązane problemy