-1

I was dabbling in OCaml when I realized that it buckets integer division and multiplication into the same precedence level, so 3*4/5 is different from 3/5*4. Somehow I incorrectly remembered that this is not the case in C/C++, and that division has higher precedence than multiplication but every piece of documentation said that exactly like OCaml C and C++ assign the same precedence to both / and *.

I wrote a simple program:

int main(int argc, char** argv){
    printf("%f %f",3*5/4, 3/5*4);
}

When I compiled this with gcc 8.1.1, it printed 0.0000 0.0000 which, although it reinforced my incorrect belief, went against the documented behavior. Suspecting some weird compiler issue, I tried to simply print an integer formatted as a float:

int main(int argc, char** argv){
        printf("%f",20);
}

and once again got 0.00000 as the result. This is really messing with my brain. It's 2AM and I cannot sleep without getting an answer.

P.S.: I have programmed in C for many years and there's either something extremely silly that I am doing here or the compiler is really messing things up.

Edit: It was a silly error as pointed out in the comments. In C/C++ / will act like proper division if, at least, one of the operands is a float but it becomes integer division when both operands are integers. Also printf() cannot perform any conversion as it has no idea about the actual type of a variable. I earned at least one downvote but it will be a lasting reminder of where bad default semantics and lax typing can bite.

farhanhubble
  • 476
  • 3
  • 18
  • 1
    Operations on `int` values yields `int` values, not `float`. Try printing `20.` or `3.*5/4`. – François Andrieux Sep 27 '18 at 18:52
  • 2
    `warning: format '%f' expects argument of type 'double', but argument 2 has type 'int' [-Wformat=]` – Support Ukraine Sep 27 '18 at 18:53
  • There's no "implicit cast" here. You are passing a variadic (`...`) argument to `printf`. It is your responsibility to make sure the argument type is the proper match for the format specifier. If you need a cast - do it yourself. `printf` will not be able to understand that a cast is needed here. `printf` essentially treats the variadic arguments as a blob of binary data. – AnT stands with Russia Sep 27 '18 at 18:56
  • So embarrassing, but programming in Python for some time made me totally forget that `/` will perform integer division so `3/5*4` evaluates to 0 but what about `3*5/4`? – farhanhubble Sep 27 '18 at 18:57
  • It's 15/4 which is ... – user3386109 Sep 27 '18 at 18:58
  • @farhanhubble not enough python 2 then :) – Jean-François Fabre Sep 27 '18 at 19:00
  • First, there's no such thing as an "implicit cast". A *conversion* can be explicit or implicit. An explicit conversion is called a *cast* (syntactically a parenthesized type name followed by an expression). Second, for variadic arguments, such as arguments to `printf` other than the format string pointer, there is no implicit conversion to the required type. Narrow integer types are promoted to `int` or `unsigned int`, and `float` is promoted to `double`, but the compiler doesn't know what type is expected so it can't generate a conversion. – Keith Thompson Sep 27 '18 at 19:01
  • Right I despised Python 2 for the implicit assumption it made. – farhanhubble Sep 27 '18 at 19:01
  • @farhanhubble note that in C `5/4` evaluates to `1`, and `3/5` evaluates to `0`. – Weather Vane Sep 27 '18 at 19:04
  • 1
    @WeatherVane True, but there is no `5/4` because multiplication and division have equal precedence, and associate left to right. So it's actually `15/4`, which admittedly gives the same answer as `3*(5/4)` – user3386109 Sep 27 '18 at 19:07

1 Answers1

2

The short answer is:

In all cases you pass an int to printf but you have used %f so a float is expected. Passing a value of a type that doesn't match your format specifier (i.e %f) is undefined behavior.

Try:

int main(void) {
   printf("%f",20.0);  // Notice the .0 
   return 0;
}

BTW:

If you have turned compiler warnings on - example gcc -Wall -Wextra --pedantic prog.c - you would have been told something like:

warning: format '%f' expects argument of type 'double', but argument 2 has type 'int' [-Wformat=]
     printf("%f",20);

Which actually tells you what the problem. So the advice is... always set your compiler to highest warning level and take all warnings seriously.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63