2

I am coding in Code::Blocks, in the C programming language:

#include <stdio.h>

int main() {
    float var1 = 3.145926535897932;
    double var2 = 3.145926535897932;
    long double var3 = 3.14159265389793213456;
    printf("%d\n", sizeof(float));
    printf("%d\n", sizeof(double));
    printf("%d\n", sizeof(long double));
    printf("%.16f\n", var1);
    printf("%.16f\n", var2);
    printf("%.21Lf\n", var3);
    return 0;
}

I am getting output as:-

4
8
16
3.1459264755249023
3.1459265358979320
0.000000000000000000000

Why am I getting 0.000000000000000000000 instead of 3.14159265389793213456, does my system does not support long double or is there a mistake in my code? And if long double does not work in my system how it is able to give output of size of long double?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Your code looks (mostly) fine. Some systems do indeed have trouble with `printf` and `long double` or `long long`. – Steve Summit Jan 29 '22 at 13:23
  • 2
    You've got a slight problem with the first three printfs, because `sizeof` doesn't return `int`. To make it fully portable, you need `printf("%zu\n", sizeof(float))`, or `printf("%d\n", (int)sizeof(float))`, or something like that. – Steve Summit Jan 29 '22 at 13:25
  • On my system, the code prints `4 8 16 3.1459264755249023 3.1459265358979320 3.141592653897931963769`, more or less as expected. – Steve Summit Jan 29 '22 at 13:27
  • 8
    So it looks like what's happening is that your *compiler* supports `long double`, but your *C runtime library* (and specifically the implementation of `printf` in it) does not. – Steve Summit Jan 29 '22 at 13:27
  • Possibly delayed effects of the undefined behaviour from using `%d` to print `size_t` types. Use `%zu` for the first 3 `printf` and try again. – Adrian Mole Jan 29 '22 at 13:30
  • @AdrianMole The C libraries that don't support `%Lf` are very likely to not support `%zd` either (since both were added in C99). I would recommend `%lu` with an `(unsigned long)` cast instead. – zwol Jan 29 '22 at 14:25
  • 1
    What compiler and version is CodeBlocks using? – dbush Jan 29 '22 at 15:47

1 Answers1

0

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
chqrlie
  • 131,814
  • 10
  • 121
  • 189