I'm just starting to learn C moving from C++, and I was just trying out a ton of variable types. I am using the MingGW-w64 toolset with the GCC compiler. This version supposedly uses UCRT runtime instead of MSVCRT. I've heard long doubles are the same as doubles using MSVCRT, but UCRT appears to use 128 bits for long double and 64 for doubles. However, I am having a very strange issue with long doubles. I am using the correct "%Lg" for printf according to Google. I have tried "%llf," "%Lf," and "%Le," but they all return the same. I first defined PI as #define M_PI 3.1415926535897932384626433832795028841971693993751L
since "math.h" does not appear to have M_PI defined. Casting it to a double appears to return the correct value, but the long double value is extremely small. What's going on? I realize a double will be good enough, but I am just wondering what the issue is.
I realize I don't need to create a const variable for the define. I was just messing around.
The only mention I can find is that long double is broken in MinGW, but that is for the MSVCRT version, not UCRT.
#include <stdio.h>
#include <math.h>
#define M_PI 3.1415926535897932384626433832795028841971693993751L
int main(void) {
const long double PI = M_PI;
printf("Size of double: %d\n", (int)sizeof(double));
printf("Size of long double: %d\n", (int)sizeof(long double));
printf("PI == %.6Lg\n", PI);
return 0;
}
Output:
Size of double: 8
Size of long double: 16
PI == 3.10817e-317
The tasks.json file I am using in Visual Studio Code is as follows. Note that I am a newb at compiling like this, so I may have made some mistakes.
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: gcc.exe build active file",
"command": "C:\\mingw64\\bin\\gcc.exe",
"args": [
"-m64",
"-std=c11",
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "compiler: C:\\mingw64\\bin\\gcc.exe"
}
]
}
printf("PI == %.6Lg %.6Lg %.6Lg %.6Lg %.6Lg %.6Lg\n", PI);
???!? How many%
format specifiers are in that format string? How many values ofPI
are you passing? Are those numbers the same: "If there are insufficient arguments for the format, the behavior is undefined." – Stanwinprintf
. But try assigning thelong double
value back to a normaldouble
and then print the result, to confirm it's correct. If so, then I'd say yourprintf
thinkslong double
is 64 bits (or at least, something different from what your compiler is using). – Gabriellong double
has the same binary representation asdouble
, but MinGW-w64 uses extended precisionlong double
. So UCRT'sprintf
andscanf
family functions are incompatible with MinGW-w64'slong double
type. – MorrisonPI
- perhaps surrounding memory?. An interesting test would be to pad the surrounding memory ofPI
with zeros. It might make for a zero final output.const long double PI = M_PI;
-->const char a[16] = { 0 }; const long double PI = M_PI; const char b[16] = { 0 };
– Moor-mlong-double-64
(gcc.gnu.org/onlinedocs/gcc/…). (which makeslong double
use the same binary format asdouble
, although for the strict-aliasing ruledouble*
andlong double*
are still not compatible.) Does MinGW come with or have available a C library that knows how to printf an 80-bit x87 extended-precision float, so the OP can actually play with it? – Schleswigholsteinprintf("%Lf\n, (long double)foo)
will look for a 64-bitdouble
as its second arg in RDX (which the caller needs to set equal to XMM1, so variadic functions don't need to know which arg has which type when dumping args to shadow space to create an array of 8-byte args contiguous with the stack args). If the caller thought it was passing along double
on the stack, it won't have set RDX to anything. Tryprintf("%Lf", 0x4002000000000000ULL)
(2.25) godbolt.org/z/foPWYvEK6 – Schleswigholstein-mlong-double=BITS
option to be different from the target ABI. TBH, I don't know why they even chose to use extended precision for MinGW in the first place. – Morrison-mlong-double-64
for ABI compat with MSVC, like they do for every other type and for struct layout I think. – Schleswigholstein