Win7 64-bit
gcc 4.8.2
g++ -Wall
I tried to format my C++ sscanf as defined in Why does scanf() need "%lf" for doubles, when printf() is okay with just "%f"? but the return is x == 0. The program is given below. I can't figure out what I did wrong so any advice is welcome.
# include <stdio.h>
# include <ios>
# include <iostream>
# include <iomanip>
#include <cstdlib>
using namespace std;
int main(int argc, char** argv) {
char buffer[30];
double x = 5.0;
sprintf(buffer, "%a", 1.2);
sscanf(buffer, "%la", &x);
cout << " Example 1.2 buffer -> " << buffer << endl;
cout << " Example 1.2 scanf <- " << x << endl;
return 0;
}
output
Example 1.2 buffer -> 0x1.3333333333333p+0
Example 1.2 scanf <- 0
Return Value The scanf() function returns the number of fields that were successfully converted and assigned. The return value does not include fields that were read but not assigned. The return value is EOF for an attempt to read at end-of-file if no conversion was performed.
In scanf() you usually pass an array to match a %s specifier, then a pointer to the first element of the array is used in it's place. For other specifiers like %d you need to pass the address of the target variable to allow scanf() to store the result in it.
A white-space character causes the scanf() function to read, but not to store, all consecutive white-space characters in the input up to the next character that is not white space. One white-space character in format-string matches any combination of white-space characters in the input.
Techopedia Explains Scanf%c — Character. %d — Signed integer. %x — Unsigned integer in hexadecimal format. %f — Floating point.
[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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With