sscanf doesn't handle hexadecimal float but strtod does

Brian Inglis Brian.Inglis@SystematicSw.ab.ca
Mon Apr 19 15:07:13 GMT 2021


On 2021-04-18 22:09, Keith Thompson via Cygwin wrote:
> The *scanf() functions don't handle hexadecimal floating-point input
> (for example "0x1p+0" representing 1.0).
> 
> A test program:
> 
> #include <stdio.h>
> int main(void) {
>      int ok = 1;
>      float x = -1.0;
>      int result = sscanf("0x1p+0", "%f", &x);
>      const float expected_x = 1.0;
>      const int expected_result = 1;
>      printf("sscanf returned %d", result);
>      if (result != expected_result) {
>          ok = 0;
>          printf(" (expected %d)", expected_result);
>      }
>      printf(", x = %g", x);
>      if (x != expected_x) {
>          ok = 0;
>          printf(" (expected %g)", expected_x);
>      }
>      puts(ok ? ", PASSED" : ", FAILED");
> }
> 
> On Cygwin, the output (compiled with gcc or clang) is:
> 
> sscanf returned 1, x = 0 (expected 1), FAILED
> 
> On Ubuntu, the output is:
> 
> sscanf returned 1, x = 1, PASSED
> 
> Looking through the newlib sources (git://sourceware.org/git/newlib-cygwin.git),
> this might be related to the _WANT_IO_C99_FORMATS macro, but I haven't
> looked into
> the details.
> 
> The test case passes on Cygwin when compiled with i686-w64-mingw32-gcc
> or x86_64-w64-mingw32-gcc.

This seems like an oversight as gdtoa-gethex.c was added about 2006 and scanf 
and strtod support it.
See augmented STC with strtod added attached:

$ gcc -o hexfloat-scanf-test{,.c}
$ ./hexfloat-scanf-test
sscanf returned 2, unscanned 'x1p+0', x = 0 (expected 1), FAILED
strtod unscanned '', x = 1, PASSED

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

This email may be disturbing to some readers as it contains
too much technical detail. Reader discretion is advised.
[Data in binary units and prefixes, physical quantities in SI.]
-------------- next part --------------
/* hexfloat-scanf-test.c - test 0x#[Pp]# sscanf and strtod support */

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

int main(void) {
    const double    expected_x	    = 0x1p+0;
    double	    x		    = -0x1p+0;
    const int	    expected_result = 2;
    int		    result	    = 0;
    int		    ok		    = 1;
    const char *    test	    = "0x1p+0";
    char *	    endp	    = NULL;
    char	    buff[BUFSIZ]    = { 0 };


    /* test sscanf() */
    result  = sscanf(test, "%la %s", &x, buff);
    printf("sscanf returned %d", result);

    if (result != expected_result) {
        ok  = 0;
        printf(" (expected %d)", expected_result);
    }

    printf(", unscanned '%s', x = %g", buff, x);

    if (x != expected_x) {
        ok  = 0;
        printf(" (expected %g)", expected_x);
    }

    printf("%s\n", ok ? ", PASSED" : ", FAILED");

    /* test strtod() */
    x	= strtod(test, &endp);

    printf("strtod unscanned '%s'", endp);

    if (!(ok = (NULL != endp && !*endp))) {
        printf(" (expected '')");
    }

    printf(", x = %g", x);

    if (x != expected_x) {
        ok = 0;
        printf(" (expected %g)", expected_x);
    }

    printf("%s\n", ok ? ", PASSED" : ", FAILED");
}



More information about the Cygwin mailing list