Detectando falla de strtol

¿Cómo puedo detectar si strtol () no convirtió un número? Lo probé en el siguiente caso simple y dio como resultado 0. La pregunta obvia ahora es ¿cómo diferenciar entre una no conversión y la conversión de 0?

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

La statement de strtol en stdio.h es la siguiente:

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

strtol proporciona un sólido esquema de comprobación y validación de errores que le permite determinar si el valor devuelto es valid o invalid . Esencialmente, tienes 3 herramientas principales a tu disposición. (1) el valor devuelto, (2) el valor errno se establece en la llamada y (3) las direcciones y el contenido de nptr y endptr proporcionan y se establecen mediante strtol . (Consulte man 3 strtol para obtener detalles completos; el ejemplo en la página de man también proporciona un conjunto más corto de condiciones para verificar, pero se han ampliado a continuación para su explicación).

En su caso, solicite un valor de retorno de 0 y determine si es válido. Como ha visto, un valor 0 devuelto por strtol no significa que el número leído fue 0 o que 0 es válido. Para determinar si 0 es válido, también debe mirar el valor errno se estableció durante la llamada (si se estableció). Específicamente, si errno != 0 y el valor devuelto por strtol es 0 , entonces el valor devuelto por strtol es INVALID . (esta condición representará una invalid base , underflow o overflow con errno igual a EINVAL o ERANGE ).

Hay una segunda condición que puede hacer que strtol devuelva un INVALID 0 . El caso en el que no se leyeron dígitos dentro de la entrada. Cuando esto ocurre, strtol establece el valor de endptr == nptr . Por lo tanto, también debe verificar si los valores del puntero son iguales antes de concluir que se ingresó un valor de 0 . (se puede ingresar un 0 VÁLIDO con varios 0's en la cadena)

A continuación se proporciona un breve ejemplo de las diferentes condiciones de error que se deben verificar al evaluar el retorno de strtol junto con varias condiciones de prueba diferentes:

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

salida:

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