[PATCH] libcxx + MingW: correct printout of long doubles

Yaron Keren yaron.keren at gmail.com
Fri Oct 4 13:06:18 PDT 2013


Hi,

Long ago Microsoft had decided (
http://msdn.microsoft.com/en-us/library/9cx8xs15.aspx) to make the long
double type in Visual C++ same as double, 64 bit. This was an incredibly
stupid decision, at least for those of us who actually care about numeric
accuracy.

MingW, gcc-based port for Windows, had kept 80-bit long doubles and so does
clang. This is a good decision which enable using these compilers in
numeric code where 80 bit long doubles are required.

However, MingW uses the Microsoft runtime DLL msvcrt.dll. Here lies a
problem: while gcc creates 80 bits long doubles, the MS runtime accepts 64
bit long doubles only. The problem is usually not obvious since the long
double is casted to a double, as in:

 exp(10.0L)

where the 10.0L will be silently cast to 10.0 and the routine will seem to
work.

However, in the *printf and *scanf family of functions arguments are not
downcasted from long double to double (float does cast to double). For
instance, naively compiling

 printf("%Lf\n",2345.0L);

with gcc or clang with the MingW runtime will print garbage results.

The MingW developers did develop a solution to the problem, namely
alternative __mingw_printf and __mingw_scanf family of functions that
accept long double 80 bit arguments properly.  In order to use the correct
rotuines, one has to

#define __USE_MINGW_ANSI_STDIO 1

which is not the default in libc but it is defined in gcc libstdc++ library
header "os_defines.h" as default.

So, the first patch to make libcxx print long doubles is to define
__USE_MINGW_ANSI_STDIO in __config. This will get the *printf and *scanf
functions working back on long doubles at least when libcxx is #included
(not in programs which do not include it, of course).

However, it will not make std::cout<<long_double work correctly. Why?
std::cout calls do_put which uses snprintf_l and asprintf_l to actually do
the work.

asprintf_l is implemented to call vasprintf_l which calls MingW vasprintf
which can handle long doubles if __USE_MINGW_ANSI_STDIO is defined. OK.
snprintf_l however is #defined to _snprintf_l, a function from msvcrt.dll
which does not support 80 bit long doubles. Problem.

Therefore, the second part of the patch implements snprintf_l  function in
a way similar to the other functions in src/support/win32/locale_win32.cpp
and locale_win32.h, calling upon vsnprintf for which there is a MingW
correct version.

Yaron
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131004/909fb117/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mingw_long_double.diff
Type: application/octet-stream
Size: 2021 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131004/909fb117/attachment.obj>


More information about the cfe-commits mailing list