From: Keith M. <kei...@us...> - 2009-02-07 14:44:19
|
On Thursday 05 February 2009 14:52:26 Aron Rubin wrote: > passing doubles to %lf appears to be broken for printf and fprintf Why do you think that? What effect do you expect `%lf' to have? Here's what POSIX, (and AFAICT also ISO C99) have to say about it: http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html |l (ell) | Specifies that a following d, i, o, u, x, or X conversion | specifier applies to a long or unsigned long argument; [... | ...] or has no effect on a following a, A, e, E, f, F, g, or G | conversion specifier. So I guess you might expect that it would have no effect; if so, why use it at all? In any case, with MinGW, you are not working with a POSIX compliant system, so MSDN trumps POSIX, and it has this to say: http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx |To specify | Use prefix | With type specifier | [...] | | |long double | l or L | f Note that `L' is standards conformant, but `l' is Microsoft specific; (why they even bother with a long double specifier at all, I've no idea, since their long double type seems to be indistinguishable from double anyway[*]). In any case, MinGW *does* implement a long double type, with 80 bits, where double, as in MSVC, is 64-bit, (which means that MSVCRT.DLL's printf() routines could never print MinGW's long doubles without casting to double). Now, since mingwrt-3.15, MinGW has provided a new implementation of the entire printf() function family, and this treats long doubles as precisely that: the MinGW 80-bit type! (Previously this capability was supported only by the snprintf() and vsnprintf() functions, for which MinGW has provided it's own implementation for several years). Now, if you use the new MinGW printf() implementation, (you don't get it by default, and you didn't say if you specified it), then *all* formatting operations are handled by the __mingw_pformat() function, and in the source (http://tinyurl.com/ark9jv) for that you will see: | case 'l': | /* | * Interpret the argument as explicitly of a | * `long' or `long long' data type. | */ | [...code for long and long long integer types elided...] | |# ifndef _WIN32 | /* | * Microsoft's MSVCRT implementation also uses `l' | * as a modifier for `long double'; if we don't want | * to support that, we end this case here... | */ | state = PFORMAT_END; | break; | | /* otherwise, we simply fall through... | */ |# endif | | case 'L': | /* | * Identify the appropriate argument as a `long double', | * when associated with `%a', `%A', `%e', `%E', `%f', `%F', | * `%g' or `%G' format specifications. | */ | stream.flags |= PFORMAT_LDOUBLE; | state = PFORMAT_END; | break; so, if you specify `%lf', we take MSDN at its word, interpret it as an explicit reference to `long double', (and maybe that is one Microsoft compatibility step too far, since MSVCRT doesn't actually have any distint `long double' data type). > (but not sprintf). That makes no sense at all; if you use MinGW's new implementation of printf(), then *all* of these functions use the same formatting code, (they *all* call __mingw_pformat()). OTOH, if you use the MSVCRT functions, then it's just as it's always been. The more likely explanation of the perceived difference is that, in the sprintf() case you've called the MSVCRT function, whereas you've called the new MinGW function in the other cases. > Either I get > many digits or zero. I was to guess I would say it is considering > %lf as long double instead of double. That's what MSDN says it should do; no need to guess. > [...] > I have changed all of my formats to %f That's sensible anyway; `%lf' is non-standard, non-portable and might well be described as a coding error, (i.e. a bug in *your* code). > because that works for double > as well as floats (which are upconverted to double in variadic > calls). `floats' are promoted to double in *all* function calls, (not just variadic); this is required by the ISO C standard, (and always has been, AFAIK). [*] http://msdn.microsoft.com/en-us/library/9cx8xs15.aspx -- Regards, Keith. |