2

I need to losslessly represent a double precision float in a string, and so I am using

sprintf(buf, "%la", x);

This works fine on my system, but when built on MinGW under Windows, gives a warning:

unknown conversion type character 'a' in format

I coded up a workaround for this case, but have trouble detecting when I should use the workaround -- I tried #if __STDC_VERSION__ >= 199901L, but it seems Gcc/MinGW defines that even if it doesn't support %a. Is there another macro I could check?

crowding
  • 1,498
  • 10
  • 11
  • 3
    How about having a look into the standard? http://port70.net/~nsz/c/c11/n1570.html#7.21.6.1 ? If your environment does not support this, it is not compliant. – too honest for this site Aug 24 '16 at 00:56
  • 1
    What does `-v` report for version information? – jxh Aug 24 '16 at 01:14
  • I don't have the compiler environment easily accessible -- I am getting the log from a package build service. – crowding Aug 24 '16 at 01:15
  • GCC doesn't support `%a` directly, it relies on the library implementation to actually do it. Does your MinGW use `glibc`? – jxh Aug 24 '16 at 01:21
  • 2
    MS Visual C is not C99 compliant, so its runtime library may not support `%a`. If MinGW is using the MS Visual C runtime, then it wouldn't support `%a` either. – jxh Aug 24 '16 at 01:22
  • 1
    To solve the higher level problem "need to losslessly represent a double precision float in a string", consider using `"%.*e"` [Printf width specifier to maintain precision of floating-point value](http://stackoverflow.com/q/16839658/2410359) Works back to C89. – chux - Reinstate Monica Aug 24 '16 at 01:32
  • @chux: The `*` specifies a variable precision, requiring an additional argument. Not sure how that would differ from a constant here. And that is not the same as `%a`. – too honest for this site Aug 24 '16 at 01:55
  • 1
    Try using mingw-w64 (mingw is an old defunct project), and define `#define __USE_MINGW_ANSI_STDIO 1`, this will make it use its own printf implementation instead of referring to microsoft's broken one – M.M Aug 24 '16 at 03:36
  • @M.M: Assuming that works, you should post it as an answer. – Keith Thompson Aug 24 '16 at 03:50
  • @KeithThompson my comment doesn't help with the question "How to detect if printf will support %a" . It seems OP is XY-probleming – M.M Aug 24 '16 at 03:52
  • @M.M: Hmm. Once you define that macro, you can tell that it *does* support `%a`. – Keith Thompson Aug 24 '16 at 03:55
  • ok. will wait for OP to report if it works or not – M.M Aug 24 '16 at 03:56
  • @KeithThompson do you know where I can find sample data for %a ? On my system , `double x = 3.14; printf("%a", x);` gives `0xc.8f5c285fc28f8p-2`, but [this page](http://stackoverflow.com/questions/4826842/the-format-specifier-a-for-printf-in-c) suggests that isn't the right answer. – M.M Aug 24 '16 at 04:03
  • @M.M What is wrong about `0xc.8f5c285fc28f8p-2`? It meets C spec. – chux - Reinstate Monica Aug 24 '16 at 04:06
  • @chux it's different to the expected value of `0x1.91eb86p+1` – M.M Aug 24 '16 at 04:06
  • @M.M The spec does not specify the range of the leading digit as long as it is non-zero (except for sub-normal) "... where there is one hexadecimal digit (which is nonzero if the argument is a normalized floating-point number and is otherwise unspecified) ..." Its the same value either way. – chux - Reinstate Monica Aug 24 '16 at 04:09
  • ok, if you write both in binary and offset by 3 bits then they sort of match up – M.M Aug 24 '16 at 04:11
  • make sure you're compiling with `-std=c99` or `-std=c11` of course – M.M Aug 24 '16 at 04:30

2 Answers2

3

This doesn't answer the question "How to detect if printf will support %a?" in the general case, but you can modify your compiler installation so that %a is supported.

First of all , use mingw-w64. This is an up-to-date fork of MinGW. The original version of MinGW is not well maintained and does not fix bugs such as you are experiencing (preferring to blame Microsoft or something).

Using mingw-w64 4.9.2 in Windows 10, the following code works for me:

#include <stdio.h>

int main()
{
    double x = 3.14;
    printf("%a\n", x);
}

producing 0x1.91eb85p+1 which is correct. This is still deferring to the Microsoft runtime.


Your question mentions %la, however %a and %la are both the same and can be used to print either a float or a double argument.

If you want to print a long double, then the Microsoft runtime does not support that; gcc and MS use different sizes of long double. You have to use mingw-w64's own printf implementation:

#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>

int main()
{
    long double x = 3.14;
    printf("%La\n", x);
}

which outputs 0xc.8f5c28f5c28f8p-2. This is actually the same number as 0x1.91eb85p+1 with more precision and a different placement of the binary point, it is also correct.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • `0xc.8f5c28f5c28f8p-2 = 3.140000000000000124344978758017532527446746826171875 (3.14)` and `0x1.91eb85p+1 = 3.13999998569488525390625 (3.1399999856948853)` – MikeM Jun 01 '18 at 20:37
2

As jxh already suspected, MingW uses the MSVCRT LibC from Windows. The C99 support is not complete, especially some of the options of printf(3) like a are missing.

deamentiaemundi
  • 5,502
  • 2
  • 12
  • 20
  • 2
    To answer the actual question, `#ifdef __MINGW32__` is probably sufficient to decide to use the workaround. – jxh Aug 24 '16 at 01:32