0

c-programming output printf()

Hi guys,

I have a question to following code: `

#include <stdio.h>
int main() {
    printf("%f\n", (8/5)/2);
    printf("%f\n", (float) 5/2);
    printf("%f\n", (8/5)/2);
    return 0;
}

Line 3 and five are the same. But output isn´t it. Why is that? I have no declaration of variables just printf() Output:

0.000000
2.500000
2.500000

But if I invert line 4 and 5 then output is same to line 3 as it should be.

#include <stdio.h>
int main() {
    printf("%f\n", (8/5)/2);
    printf("%f\n", (8/5)/2);
    printf("%f\n", (float) 5/2);
    return 0;
}
0.000000
0.000000
2.500000

Can anybody explain the output of this code?

hello447
  • 21
  • 6
  • Please see [Division result is always zero](https://stackoverflow.com/questions/2345902/division-result-is-always-zero). It might not be zero here, but integer division happens, and also an `int` is passed where `double` is expected. – Weather Vane Nov 05 '22 at 20:23
  • 3
    The first and third `printf` statements pass an integer as the parameter. Since the format string says the parameter will be a float you have undefined behavior. – Retired Ninja Nov 05 '22 at 20:26
  • You're performing integer devision, hence the result is `0`. – Marco Nov 05 '22 at 20:31
  • That´s exactly what I want. I want to make an integer division but `float` is expected. Note I have added output to question by inverting line 4 and 5 – hello447 Nov 05 '22 at 20:42
  • The first one could be `printf("%f\n", (8.0 / 5.0) / 2.0);` – Weather Vane Nov 05 '22 at 20:54
  • 3
    Floating point values are passed in one set of registers; integers in a different set of registers. Once the floating point register is set to 2.5, the integer arithmetic doesn't change it. The behaviour is undefined, but that's an explanation of what happens. Try: `printf("%f %d\n", 355.0/113.0, 355/113); printf("%f %d\n", 355/113, 355.0/113.0);` — given what you're seeing, I expect you to see the same output twice. (My Mac gives the same answer twice, even though the arguments are reordered. I also have to avoid my default compilation options — otherwise, it doesn't compile.) – Jonathan Leffler Nov 06 '22 at 00:15
  • See also [Why is the output different using `printf()`?](https://stackoverflow.com/q/33766748/15168) – Jonathan Leffler Nov 06 '22 at 04:40
  • @JonathanLeffler Thank you so much. It makes absolutely sense. The output is same as it is by you and also I understand now why. It seems the undefined behaviour is caused on hardware level with the registers. My question to you. Can you write your comment in an extra answer so I can mark as solved with green symbol than other see directly your right answer to this topic? – hello447 Nov 06 '22 at 08:43

3 Answers3

3

As I noted in a comment:

On machines such as x86/64 architecture, floating point values are passed in one set of registers; integers in a different set of registers. Once the floating point register is set to 2.5, the integer arithmetic doesn't change it. The behaviour is undefined, but that's an explanation of what happens. Try:

printf("%f %d\n", 355.0/113.0, 355/113);
printf("%f %d\n", 355/113, 355.0/113.0);

Given what you're seeing, I expect you to see the same output twice. My Mac gives the same answer twice, even though the arguments are reordered.

Source:

#include <stdio.h>

int main(void)
{
    printf("%f %d\n", 355.0/113.0, 355/113);
    printf("%f %d\n", 355/113, 355.0/113.0);
    return 0;
}

Output:

3.141593 3
3.141593 3

I note that I have to avoid my default compilation options — otherwise, it doesn't compile.

Default compilation:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common -c fl43.c
fl43.c: In function ‘main’:
fl43.c:6:14: error: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Werror=format=]
    6 |     printf("%f %d\n", 355/113, 355.0/113.0);
      |             ~^        ~~~~~~~
      |              |        |
      |              double   int
      |             %d
fl43.c:6:17: error: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘double’ [-Werror=format=]
    6 |     printf("%f %d\n", 355/113, 355.0/113.0);
      |                ~^              ~~~~~~~~~~~
      |                 |                   |
      |                 int                 double
      |                %f
cc1: all warnings being treated as errors
$
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

While your code will compile, you should receive warnings about passing an int where a double was expected. The result is undefined behavior.

% gcc test.c
test.c:3:20: warning: format specifies type 'double' but the argument has type 'int' [-Wformat]
    printf("%f\n", (8/5)/2);
            ~~     ^~~~~~~
            %d
test.c:5:20: warning: format specifies type 'double' but the argument has type 'int' [-Wformat]
    printf("%f\n", (8/5)/2);
            ~~     ^~~~~~~
            %d
2 warnings generated.
Chris
  • 26,361
  • 5
  • 21
  • 42
  • 3
    _Undefined_ behavior is just that: undefined. It can work properly. Or not. – Chris Nov 05 '22 at 20:40
  • That´s not undefined behaviour. The `int ` term commits to `%f`. This is okay because `float` has 4 bytes and `int ` too. Just math result is wrong sure but note if you want to commit `double` expression to `int` this execute undefined behaviour cause `double` has 8 bytes – hello447 Nov 05 '22 at 20:59
  • https://stackoverflow.com/questions/38597274/why-does-printff-0-give-undefined-behavior – Chris Nov 05 '22 at 21:12
  • I would clarify "work properly" to "work the way you _expect_". Without a definition for the behavior, there is not really a "proper" way for it to work. – Chris Nov 05 '22 at 21:15
  • @hello447, note that `%f` does not mean `float` but `double`! So it *is* Undefined Behaviour. – wovano Nov 06 '22 at 19:30
1

It is one big undefined behaviour as you pass integer but ask printf to print double

You need to to cast the result:

    printf("%f\n", (double)((8/5)/2));
    printf("%f\n", (double) 5/2);
    printf("%f\n", (double)((8/5)/2));
0___________
  • 60,014
  • 4
  • 34
  • 74