On my system (OS/X with clang), I get the expected output:
4
8
16
3.1459264755249023
3.1459265358979320
3.141592653897931963769
Yet the compiler produces many warnings:
clang -O3 -funsigned-char -std=c11 -Weverything -Wno-padded -Wno-shorten-64-to-32 -Wno-missing-prototypes -Wno-vla -Wno-missing-nor
eturn -Wno-sign-conversion -Wno-unused-parameter -Wwrite-strings -lm -lcurses -o 220306-longdouble 220306-longdouble.c
220306-longdouble.c:4:18: warning: implicit conversion loses floating-point precision: 'double' to 'float' [-Wconversion]
float var1 = 3.145926535897932;
~~~~ ^~~~~~~~~~~~~~~~~
220306-longdouble.c:6:24: warning: implicit conversion increases floating-point precision: 'double' to 'long double'
[-Wdouble-promotion]
long double var3 = 3.14159265389793213456;
~~~~ ^~~~~~~~~~~~~~~~~~~~~~
220306-longdouble.c:7:20: warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
printf("%d\n", sizeof(float));
~~ ^~~~~~~~~~~~~
%lu
220306-longdouble.c:8:20: warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
printf("%d\n", sizeof(double));
~~ ^~~~~~~~~~~~~~
%lu
220306-longdouble.c:9:20: warning: format specifies type 'int' but the argument has type 'unsigned long' [-Wformat]
printf("%d\n", sizeof(long double));
~~ ^~~~~~~~~~~~~~~~~~~
%lu
220306-longdouble.c:10:23: warning: implicit conversion increases floating-point precision: 'float' to 'double'
[-Wdouble-promotion]
printf("%.16f\n", var1);
~~~~~~ ^~~~
6 warnings generated.
Here are the explanations:
- the value produced by the
sizeof
operator has type size_t
which is different from int
: you should either case it as (int)
or use the printf
conversion specifier %zu
.
- the
float
value should be initialized from a float
constant: float var1 = 3.145926535897932F;
- the
long double
value should be initialized from a long double
constant: long double var1 = 3.145926535897932L;
- In the call
printf("%.16f\n", var1)
, var1
is implicitly converted to type double
as specified for variable arguments in vararg functions. You might make this conversion explicit to silence this warning, showing the behavior is expected.
- the call
printf("%.21Lf\n", var3);
conforms to the C99 Standard, but the C library on your system seems incompatible with the compiler in use regarding the type long double
.
Microsoft decided more than 10 years ago to map type long double
to type double
in their tools (cf Why did Microsoft abandon long double data type? ).
The compiler you use on your system seems to handle long double
in a different way that is incompatible with the C library your program links to. It is also possible that this library does not conform to the C99 specification, eg: the %Ld
conversion for type long double
, or uses a different ABI to pass long double
values. Older Microsoft C libraries are known to have such problems decades after the C Standard was published. You should try and upgrade the system or switch to a conformant C development system.
Here is a modified version, that no longer has undefined behavior, but probably still won't produce the expected output on your system:
#include <stdio.h>
int main() {
float var1 = 3.145926535897932F;
double var2 = 3.145926535897932;
long double var3 = 3.14159265389793213456L;
printf("%d\n", (int)sizeof(float));
printf("%d\n", (int)sizeof(double));
printf("%d\n", (int)sizeof(long double));
printf("%.16f\n", (double)var1);
printf("%.16f\n", var2);
printf("%.21Lf\n", var3);
return 0;
}
Output:
4
8
16
3.1459264755249023
3.1459265358979320
3.141592653897931963769