C, pre and post increment, different answers in different programs

152 views Asked by At

testing some code when studying C language,

#include <stdio.h>
#include <math.h>
#define hypotenusa(x, y)  sqrt((x) * (x) + (y) * (y))

int main(void) {
    int a, x;
    x = 2;
    a = hypotenusa(++x, ++x);
    printf("%d\n", a);
}

And I am getting the answer

  • 6 in one program(dosbox gcc compiler)
  • 7 in codelight gcc compiler and
  • 8 on codeChef online compiler

can anyone explain this behaviour? my logic says it should be 6 (sqrt(42)) but...

3

There are 3 answers

1
P.P On BEST ANSWER

It's undefined behaviour.

After the macro replacement

a = hypotenusa(++x, ++x);

becomes:

a = sqrt((++x) * (++x) + (++x) * (++x));

As you can see x is modified multiple times without any intervening sequence point(s). See What Every C Programmer Should Know About Undefined Behavior.

0
John Bode On

The behavior of your macro is undefined, meaning any result is possible.

Chapter and verse

6.5 Expressions
...
2     If a side effect on a scalar object is unsequenced relative to either a different side effect
      on the same scalar object or a value computation using the value of the same scalar object,
      the behavior is undefined. If there are multiple allowable orderings of the subexpressions
      of an expression, the behavior is undefined if such an unsequenced side effect occurs in any
      of the orderings.84)
84) This paragraph renders undefined statement expressions such as
    i = ++i + 1;
    a[i++] = i;
      while allowing
    i = i + 1;
    a[i] = i;

Basically, if you modify the value of an object more than once in an expression, or both modify an object and use its value in a computation in an expression, the result will not be well-defined unless there is a sequence point in between those operations. With a few exceptions, C does not force left-to-right evaluation of expressions or function parameter evaluations, nor does it mandate that the side effect of ++ or -- be applied immediately after evaluation. Thus, the result of an expression like x++ * x++ will vary from platform to platform, program to program, or even potentially from run to run (although I've never seen that in practice).

For example, given the expression y = x++ * x++, the following evaluation sequence is possible:

t0 <- x        // right hand x++, t0 == 2
t1 <- x        // left hand x++, t1 == 2
y <- t0 * t1   // y = 2 * 2 == 4
x <- x + 1     // x == 3
x <- x + 1     // x == 4

which doesn't give you the result you expect if you assume left-to-right evaluation.

3
Aganju On

hypotenusa(++x, ++x) is undefined behavior.
It is up to the compiler which of the parameters gets incremented (and pushed) first - after the macro expansion, there are a total of four instances, and the sequence is not defined.

You should never increment the same variable multiple times in the same statement, to avoid this kind of issues. Using a variable twice in a macro can hide this error and make it really nasty.