0

Why the code only works when I use the %lf or %f place holder (second placeholder), but its printing 0 when I use %d?

#include <stdio.h>

void main()
{

    long id;
    id = 123456789;
    double Hourly;
    Hourly = 30;
    int HoursAday, daysAweek, Fired, Hired;
    HoursAday = 8; daysAweek = 5; Fired = 2021; Hired = 2019;
    printf("bob, id: \"%d\" should get %lf", id, (Hourly * HoursAday * daysAweek) * (Fired - Hired));

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
jypedud
  • 15
  • 2
  • 2
    `%d` is for `int` values. `%lf` (and `%f` but only for `printf`) is for `double` values. This should have been explained in any decent book, class or tutorial. Mismatching format specifier and argument value type leads to *undefined behavior*. – Some programmer dude Oct 25 '21 at 17:30
  • 1
    `void main()` should be `int main()` – Kevin Oct 25 '21 at 17:31
  • You could cast the float value to int, and lose the decimals part (if values are in range of course) – Déjà vu Oct 25 '21 at 17:31
  • Why @Kevin? It compiles and returns `0` as expected... – Matthieu Oct 25 '21 at 17:33
  • I wonder why the "In C" was edited out ?? While there is the C tag, reading the question in context is easier to follow. – Déjà vu Oct 25 '21 at 17:37
  • 2
    @Matthieu: Because C 2018 5.1.2.2.1 1 says “The function called at program startup is named `main`. The implementation declares no prototype for this function. It shall be defined with a return type of `int` and with no parameters:…” The fact that the compiler you tested with accepted it does not mean that other compilers will, or even that your compiler will accept it with different switches or even that programs with `void main()` other than the one you tried will work. – Eric Postpischil Oct 25 '21 at 17:37
  • 1
    @Matthieu See https://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c. It's more strict in C++, but still in C you should use `int main()` or `int main(int, char**)` – Kevin Oct 25 '21 at 17:37
  • 1
    @Breakingnotsobad: It is redundant when the C tag is present. – Eric Postpischil Oct 25 '21 at 17:37
  • 1
    @Kevin: `int main(void)` is shown in the C standard and is preferred, although `int main()` is equivalent in definitions (but not in declarations that are not definitions). – Eric Postpischil Oct 25 '21 at 17:38
  • 2
    Even the code as-is already should complain about a formatting mismatch of the *first* argument, let alone the *second*. Compile with warnings enabled. Always. – Cheatah Oct 25 '21 at 17:39

2 Answers2

3

The type of (Hourly * HoursAday * daysAweek) * (Fired - Hired) is double so the correct specifier is %lf. Because of variadic arguments default conversions the code will also work with %f (*). But %d is undefined behavior.

Also, the correct specifier for id (which is of type long) is %ld. %d is undefined behavior.

See the documentation for printf: https://en.cppreference.com/w/c/io/fprintf

(*) A float variadic argument always gets converted to double. So the printf family of functions will never receive a float, they will always receive a double. That's why %f and %lf are for practical reasons equivalent.

bolov
  • 72,283
  • 15
  • 145
  • 224
2

This expression

(Hourly * HoursAday * daysAweek) * (Fired - Hired)

has the type double due to the usual arithmetic conversions because the variable Hourly has the type double. That is if one operand has the type double and other operand has an integer type in a binary operation then the operand with the integer type is converted to the type double.

Using the wrong conversion specifier %d designed to output objects of the type int with an object of the type double invokes undefined behavior.

Pay attention to that in this conversion specifier %lf the length modifier l has no effect. So it is enough to use %f.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335