Różnica między scanf () i strtol () / strtod () w parsowaniu liczb
Uwaga: Całkowicie przerobiłem pytanie, aby lepiej odzwierciedlało to, za co ustalam nagrodę. Proszę wybaczyć wszelkie niezgodności z już podanymi odpowiedziami, które mogły powstać. Nie chciałem tworzyć nowego pytania, ponieważ poprzednie odpowiedzi na to pytanie mogą być pomocne.
Pracuję nad implementacją standardowej biblioteki C i jestem zdezorientowany co do jednego określonego rogu standardu.
Standard definiuje formaty liczb akceptowane przezscanf
rodzina funkcji (% d,% i,% u,% o,% x) pod względem definicji dlastrtol
, strtoul
, istrtod
.
Standard również to mówifscanf()
wrzuci tylko maksymalnie jeden znak do strumienia wejściowego, a zatem niektóre sekwencje zostaną zaakceptowane przezstrtol
, strtoul
istrtod
są nie do przyjęciafscanf
(ISO / IEC 9899: 1999, przypis 251).
Próbowałem znaleźć pewne wartości, które mogłyby wykazywać takie różnice. Okazuje się, że szesnastkowy prefiks „0x”, po którym następuje znak, który nie jest cyfrą szesnastkową, jest jednym z takich przypadków, w którym dwie rodziny funkcji różnią się.
Co ciekawe, stało się jasne, że dwie dostępne biblioteki C wydają się nie zgadzać na wyjściu. (Zobacz program testowy i przykładowe wyjście na końcu tego pytania).
Chciałbym usłyszećco byłoby uważane za zgodne ze standardem zachowanie w parsowaniu „0xz”?. Najlepiej byłoby cytować odpowiednie części ze standardu, aby podkreślić znaczenie.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main()
{
int i, count, rc;
unsigned u;
char * endptr = NULL;
char culprit[] = "0xz";
/* File I/O to assert fscanf == sscanf */
FILE * fh = fopen( "testfile", "w+" );
fprintf( fh, "%s", culprit );
rewind( fh );
/* fscanf base 16 */
u = -1; count = -1;
rc = fscanf( fh, "%x%n", &u, &count );
printf( "fscanf: Returned %d, result %2d, consumed %d\n", rc, u, count );
rewind( fh );
/* strtoul base 16 */
u = strtoul( culprit, &endptr, 16 );
printf( "strtoul: result %2d, consumed %d\n", u, endptr - culprit );
puts( "" );
/* fscanf base 0 */
i = -1; count = -1;
rc = fscanf( fh, "%i%n", &i, &count );
printf( "fscanf: Returned %d, result %2d, consumed %d\n", rc, i, count );
rewind( fh );
/* strtol base 0 */
i = strtol( culprit, &endptr, 0 );
printf( "strtoul: result %2d, consumed %d\n", i, endptr - culprit );
fclose( fh );
return 0;
}
/* newlib 1.14
fscanf: Returned 1, result 0, consumed 1
strtoul: result 0, consumed 0
fscanf: Returned 1, result 0, consumed 1
strtoul: result 0, consumed 0
*/
/* glibc-2.8
fscanf: Returned 1, result 0, consumed 2
strtoul: result 0, consumed 1
fscanf: Returned 1, result 0, consumed 2
strtoul: result 0, consumed 1
*/
/* Microsoft MSVC
fscanf: Returned 0, result -1, consumed -1
strtoul: result 0, consumed 0
fscanf: Returned 0, result 0, consumed -1
strtoul: result 0, consumed 0
*/
/* IBM AIX
fscanf: Returned 0, result -1, consumed -1
strtoul: result 0, consumed 1
fscanf: Returned 0, result 0, consumed -1
strtoul: result 0, consumed 1
*/