问题
Consider the code
#include <iostream>
int main() {
std::cout << 4.2L;
}
Compiling it on MinGW and running results in the following output:
> g++ test.cc
> a.exe
-7.89773e-278
Is it a bug in MinGW and is there a fix or workaround?
Update:
There is a similar issue with printf
described in this question:
#include <cstdio>
int main() {
std::printf("%Lg", 4.2L); // prints -7.89773e-278
}
However, the issue with printf
can be fixed by defining __USE_MINGW_ANSI_STDIO
while this one can't, so I think it deserves a separate question.
回答1:
This is not a MinGW bug ... controversial as that statement may seem, the reality is that it is a limitation of Microsoft's C/C++ runtime library, upon which MinGW is dependent. As a developer, it is incumbent on you to understand the limitations of your tools, such as this one, and to work within those limitations.
The problem you are experiencing is due to Microsoft's lack of any distinct implementation of a long double
data type in MSVC, and the consequent lack of effective support for that data type within the I/O subsystem provided by MSVCRT.DLL; (and, before you tell me, perhaps indignantly, that "of course MSVC supports long double
", I know that it does syntactically, but semantically it has no distinct implementation, simply behaving by effectively ignoring the long
qualifier, such that long double
becomes a synonym for bare double
).
Conversely, GCC and hence MinGW does have an implementation of long double
, which is distinct from double
; the former is an 80-bit entity, whereas the latter is 64-bit, and is an exact analogue of MSVC's 64-bit implementation of both data types. This is great when you need the greater precision of 80-bit floating point computation, but it can lead to problems, such as you are experiencing, when it comes to output of results; (the I/O translator is handed an 80-bit raw data representation of a long double
data entity, where it expects 64-bit; the internal representations are incompatibly different, so garbage ensues when part of the mantissa is interpreted as exponent).
As you've noted, whereas MSVCRT.DLL supports only output of 64-bit double
values, MinGW does offer an alternative implementation of C's printf
style I/O, which can correctly translate the 80-bit format; however, this does not extend to supporting C++ style I/O. Thus, in C++ code, you cannot simply exploit the MinGW alternative I/O implementation, while continuing to use C++ I/O semantics; you have to recognize the MSVCRT.DLL limitation, and code your application accordingly. Some options you might consider include:--
- Forego the use of the
long double
data type, and perform your computations asdouble
; (this is the only option which is effectively available to users of Microsoft's compiler, because it doesn't really have a distinctlong double
data type implementation to begin with). - Perform the computation as
long double
, but cast the result todouble
for output. - Use C style I/O functions instead of the C++ I/O semantics, and enable MinGW's alternative
printf
implementation by compiling with any of-posix
,-D_GNU_SOURCE
,-D_BSD_SOURCE
,-D_XOPEN_SOURCE=700
, or-D_POSIX_C_SOURCE=200809L
, (or better, add#define
for any of the latter four to your source, before any#include
). If preferred, you may also substitute any earlier compliance level for_XOPEN_SOURCE
or_POSIX_C_SOURCE
; (however, please ignore the incredibly bad advice, which may be offered by some commentators, to compile with-D__USE_MINGW_ANSI_STDIO
; the double underscore, which introduces that macro name, marks it as "implementation reserved", and therefore not something which you, as an end user of the compiler implementation, should be referring to directly). - Use C's
snprintf
function to convertlong double
data to a C string representation, then use C++ semantics to output that instead of leaving C++ to translate the raw form of thelong double
entity directly. (IIRC, Microsoft don't providesnprintf
-- they provide_snprintf
instead -- so if you are careful to use the ANSI function name, you get 80-bitlong double
support automatically).
来源:https://stackoverflow.com/questions/30080618/long-double-is-printed-incorrectly-with-iostreams-on-mingw