[UPDATE: There's a bug in the Cygwin runtime library "newlib" dealing with hexadecimal floating-point input. As of April 2021, a fix has been submitted but not yet released.]
I see nothing wrong with your code. When I compile and run it on my Linux system, the output is:
Example 1.2 buffer -> 0x1.3333333333333p+0
Example 1.2 scanf <- 1.2
The %a
specifier for the *printf
and *scanf
functions was introduced in C99, and incorporated into C++11. For the sprintf
call, "%a"
is a valid format for an argument of type double
, and for the sscanf
call "%la"
is a valid format for an argument of type double*
.
The version of gcc (or g++) is not directly relevant to the problem. gcc is just the compiler; the sscanf
function is implemented by the runtime library.
When I compile and run your program under Cygwin on Windows 7, I get the same incorrect output you do. Cygwin uses the "newlib" C library, which differs from the glibc library used on most Linux systems.
If you're using a MinGW installation of gcc, if I recall correctly it uses the Microsoft C library. Microsoft's support for C standards later than 1990 is not good, so it's not too surprising if it doesn't implement sscanf
's "%la"
format correctly.
Note that you don't need to use "%la"
for hexadecimal input. For the *scanf
functions, the a
, e
, f
, and g
specifiers are all equivalent, and will accept either decimal or hexadecimal floating-point input. So you should be able to use:
sscanf(buffer, "%lf", &x);
But if "%la"
doesn't work, chances are "%lf"
won't work either.
The sscanf
function returns an int
result indicating how many items were successfully scanned. You should always check that result. (Though if my experiment on Cygwin is any guide, it won't do any good in this case; sscanf
returned 1
but still set x
to 0.0
.)
Bottom line: Your code is ok, but you're probably using a runtime library that doesn't support what you're trying to do.
Here's another program (it's straight C but it should work as C++) that should give a bit more information. sprintf
returns the number of characters written; sscanf
returns the number of items read.
#include <stdio.h>
int main(void) {
char buffer[40];
char leftover[40];
double x = 5.0;
int sprintf_result = sprintf(buffer, "%a", 1.2);
printf("sprintf returned %d, buffer = \"%s\"\n", sprintf_result, buffer);
int sscanf_result = sscanf(buffer, "%lf%s", &x, leftover);
printf("sscanf returned %d, x = %f", sscanf_result, x);
if (sscanf_result >= 2) {
printf(", leftover = \"%s\"", leftover);
}
putchar('\n');
return 0;
}
On my Linux system, I get the correct output, which is:
sprintf returned 20, buffer = "0x1.3333333333333p+0"
sscanf returned 1, x = 1.200000
Under Cygwin, I get this output:
sprintf returned 20, buffer = "0x1.3333333333333p+0"
sscanf returned 2, x = 0.000000, leftover = "x1.3333333333333p+0"
which indicates that the "%lf"
format caused sscanf
to consume just the 0
, leaving the rest of the string to be consumed by the "%s"
. This is characteristic of a C90 implementation (before "%a"
was added to the standard) -- but printf
's "%a"
works correctly.
Try this on your system.
UPDATE 7 years later: I still see the same problem with Cygwin under Windows 10. Further experimentation shows that it doesn't support either the %a
format specifier or hexadecimal floating-point input. In C99 and later, then a
, e
, f
, and g
specifiers all behave the same way, accepting decimal or hexadecimal input, so for example, a %la
format should accept input like 1.0
. I've submitted a bug report to the Cygwin mailing list: https://cygwin.com/pipermail/cygwin/2021-April/248315.html
UPDATE 2: A patch has been pushed to newlib-cygwin that should fix this, and new developer snapshots are available. If all goes well, I presume Cygwin will be updated with this fix Real Soon Now.
https://cygwin.com/pipermail/cygwin/2021-April/248323.html