Menu

#2358 scanf doesn't parse non-finite floating point strings like "Inf" and "NaN"

OTHER
doc
nobody
None
Support
wont-fix
Behaves_as_Documented
False
2017-11-30
2017-11-29
No

sscanf doesn't parse strings representing non-finite floating point values with MinGW. To reproduce, I'm compiling the follwing example with gcc from the msys shell:

#include <stdio.h>
#include <stdlib.h>

void main() {
    const char s[256];
    double d;
    float f;
    while (1) {
        d = 0.0;
        f = 0.0;
        printf("Enter value: ");
        scanf("%s",&s[0]);
        printf("s = %s\n",s);

        sscanf(s,"%lf",&d);
        printf("sscanf %%lf says d = %g\n",d);

        sscanf(s,"%f",&f);
        printf("sscanf %%f says f = %g\n",f);

        d = strtod(s,NULL);
        printf("strtod says d = %g\n",d);

        f = strtof(s,NULL);
        printf("strtof says f = %g\n\n",f);

    }
}

compile:

$ gcc scanf.c -o scanf.exe

Run:

$ scanf.exe
Enter value: 1.23
s = 1.23
sscanf %lf says d = 1.23
sscanf %f says f = 1.23
strtod says d = 1.23
strtof says f = 1.23

Enter value: 1.233
s = 1.233
sscanf %lf says d = 1.233
sscanf %f says f = 1.233
strtod says d = 1.233
strtof says f = 1.233

Enter value: nan
s = nan
sscanf %lf says d = 0
sscanf %f says f = 0
strtod says d = 0
strtof says f = -1.#IND

Enter value: inf
s = inf
sscanf %lf says d = 0
sscanf %f says f = 0
strtod says d = 0
strtof says f = 1.#INF

Enter value: iNfInIty
s = iNfInIty
sscanf %lf says d = 0
sscanf %f says f = 0
strtod says d = 0
strtof says f = 1.#INF

GCC 4.9.2 on Debian Jessie returns inf and nan in all cases as expected.

System info

OS: Windows 10

GCC:
$ gcc -v
Using built-in specs.
COLLECT_GCC=C:\MinGW\bin\gcc.exe
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe
Target: mingw32
Configured with: ../src/gcc-6.3.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --with-gmp=/mingw --with-mpfr --with-mpc=/mingw --with-isl=/mingw --prefix=/mingw --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-pkgversion='MinGW.org GCC-6.3.0-1' --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --enable-libgomp --disable-libvtv --enable-nls
Thread model: win32
gcc version 6.3.0 (MinGW.org GCC-6.3.0-1)

LD:
$ ld -v
GNU ld (GNU Binutils) 2.28

$ uname -a
MINGW32_NT-6.2 AH-RLIVINGS 1.0.19(0.48/3/2) 2016-07-13 17:45 i686 Msys

1 Attachments

Discussion

  • Ryan Livingston

    Ryan Livingston - 2017-11-29

    I've got an errant const in the code here's what it should be and the updated attachment:

    #include <stdio.h>
    #include <stdlib.h>
    
    void main() {
        char s[256];
        double d;
        float f;
        while (1) {
            d = 0.0;
            f = 0.0;
            printf("Enter value: ");
            scanf("%s",&s[0]);
            printf("s = %s\n",s);
    
            sscanf(s,"%lf",&d);
            printf("sscanf %%lf says d = %g\n",d);
    
            sscanf(s,"%f",&f);
            printf("sscanf %%f says f = %g\n",f);
    
            d = strtod(s,NULL);
            printf("strtod says d = %g\n",d);
    
            f = strtof(s,NULL);
            printf("strtof says f = %g\n\n",f);
    
        }
    }
    
     

    Last edit: Ryan Livingston 2017-11-29
  • Keith Marshall

    Keith Marshall - 2017-11-30
    • status: unread --> doc
    • Type: Bug --> Support
    • Resolution: none --> wont-fix
    • Category: Unknown --> Behaves_as_Documented
     
  • Keith Marshall

    Keith Marshall - 2017-11-30

    I'm sorry, but the only error here is in your expectations. You are using Microsoft's implementation of scanf(), (because that is all that MinGW has ever used for this function, and its siblings), so the behaviour is as Microsoft have specified it, (and there appears to be nothing in their documentation to suggest how infinities and nans might be converted, so you cannot expect any particular result). Whatever results you see on Debian Jessie, (or any other Linux distribution, or other non-Windows platform), are completely irrelevant.

    You may consider Microsoft's implementation to be broken -- and you may well be right -- but good luck with trying to get them to acknowledge that, much less fix it. If you believe you can improve on Microsoft's implementation, (and contribute an enhanced implementation for MinGW), you might consider developing a replacement similar to my pformat() implementation for the printf() family; in 25 years of C programming, I don't believe I've ever felt the need to use scanf(), (which I consider to be a poorly designed API), and I may have seen one instance of its use in other projects in which I have participated, so I don't have a great deal of incentive, (much less time), to pursue this myself.

     

    Last edit: Keith Marshall 2017-11-30
  • Ryan Livingston

    Ryan Livingston - 2017-11-30

    Thank you for the info Keith and apologies for the noise. I was unaware MinGW was using MSVCRT.dll. Instead, I assumed since the code worked with MSVC that it would work with the runtime used with MinGW. MSVCRT is not C99 compatible and the C89 standard for strtod makes no mention of non-finites. So there's no issue to purue with Microsoft as far as I see.

     
  • Keith Marshall

    Keith Marshall - 2017-11-30

    For completeness, it is probably worth mentioning that, if you define _ISOC99_SOURCE, or _XOPEN_SOURCE >= 600, or _POSIX_C_SOURCE >= 200112L, as in this example:

    #define _ISOC99_SOURCE
    
    #include <stdio.h>
    #include <stdlib.h>
    
    ssize_t get_input( char **lineptr, int *len )
    {
      printf( "Enter value (RETURN to quit): " ); fflush( stdout );
      return getline( lineptr, len, stdin );
    }
    
    int main()
    {
      ssize_t stop;
      size_t buflen = 256;
      char *input = malloc( buflen );
      while( (stop = get_input( &input, &buflen )) > 1 )
      {
        if( input[--stop] == '\n' ) input[stop] = '\0';
        printf( "strtof( \"%s\" ) reports %g\n", input, strtof( input, NULL ) );
        printf( "strtod( \"%s\" ) reports %g\n", input, strtod( input, NULL ) );
        printf( "strtold( \"%s\" ) reports %Lg\n", input, strtold( input, NULL ) );
      }
      return 0;
    }
    

    then the MinGW replacements for strtod(), and for printf() are selected, in preference to the MSVCRT.dll versions, and these should DTRT. This will not help for scanf() and siblings, though, because there are no MinGW replacements for these.

    BTW, the 1.INF and -1.IND results, seen in your example output for strtof(), are the consequence of mixing correctly interpreted INF and NaN with MSVCRT.dll's printf(). Historically, MSVCRT.dll did not provide either strtof() or strtold(), so we always used our own implementations, and 1.INF and -1.IND are MSVCRT.dll printf()'s representations for inf and nan respectively.

     
  • Ryan Livingston

    Ryan Livingston - 2017-11-30

    Thanks for the extra info, Keith. We may be able to switch to strtod and use the replacements as a workaround in our project.