1

Could you please explain why the below program's result is different?

Program :

#define MUL(X) X*X
int main()
{
  int i=3;
  cout<<MUL(++i)<<"\n";
  return 0;
}

Output :

25
pzaenger
  • 11,381
  • 3
  • 45
  • 46
Tejaswi Burgula
  • 329
  • 3
  • 14
  • 1
    Think about it. If `X` is `++i`, what is `X*X`? – juanchopanza Feb 05 '16 at 12:21
  • 2
    Different than what? – eerorika Feb 05 '16 at 12:22
  • @user2079303 Good question, but from the wording of the title, I'd guess the OP means "different from NOT passing the prefix to the macro", or, performing the `++` before calling the macro. `++i; MUL(i)` – Mr Lister Feb 05 '16 at 12:27
  • Because it's [undefined behaviour](http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points), a classic example BTW. It's expanded to `++i * ++i`, similar case to the `i++ * ++i` explained in the first answer – Mr. E Feb 05 '16 at 12:37
  • Different as in could be different on different platforms/compilers/days of the week because of undefined behaviour. Also, If you must use a macro like this, use `#define MUL(X) ((X)*(X))` (i.e. wrap uses of `X` and the whole thing in parentheses) so that "normal" uses will work (e.g. your `MUL(3+1)` gives `7` [3 + (1*3) + 1] instead of `16` [(3+1)*(3+1)]). – TripeHound Feb 05 '16 at 12:39
  • Sorry.. How the result is 25 there? I thought like (++i * ++i) means (4 * 5)=20. But here the result is different from what i expected. – Tejaswi Burgula Feb 05 '16 at 12:39
  • Nothing **can** be expected because it's undefined. It could (and seems to for you) do both increments _before_ the multiplication (5*5), it could do (4*5), (5*4) or, possibly, (4*4). – TripeHound Feb 05 '16 at 12:41
  • Oh! ok, it is undefined behaviour? But could you please explain why? And what are the other cases in macros which are undefined? – Tejaswi Burgula Feb 05 '16 at 12:47
  • @TejaswiBurgula: There are two issues here. First is that C doesn't force left-to-right evaluation of arithmetic expressions. Second is that the side effect of the `++` operator doesn't have to be applied immediately upon evaluation. This means that the result of an expression like `i++ * i++` will vary based on platform, compiler settings, even surrounding code. The language standard calls this out as *undefined behavior* so that compilers aren't required to handle the issue in any particular way; as far as the standard is concerned, *any* result is "correct". – John Bode Feb 05 '16 at 13:53
  • Right. And if you're still interested in why this particular compiler, under these particular circumstances, gives this result, it's possibly something like: the variable is stored in a register rather than a memory location. The left hand part is calculated (and stored in the register), the right hand part is calculated (and stored in the register), the multiplication is done (again, on the register). But your mileage may vary. it _will_ vary. – Mr Lister Feb 05 '16 at 14:06

1 Answers1

5

In order to analyse this, let's expand the macro, which becomes ++i * ++i.

Formally, the behaviour of ++i * ++i is undefined as * is not a sequencing point, and ++ mutates the i. So the compiler can do anything, and no further explanation is necessary.

If your compiler supports typeof (which is compile-time evaluable so will not do any incrementing), and expression statements, then the safe version of your macro is

#define MUL(i) ({    \
    typeof(i) j = (i);  \
    j*j;                \
})

although it would be wise to avoid a macro altogether and use a function.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    I'm pretty sure it's in fact UB, not just indeterminate. The two `++` have side effects on the scalar `i` in unsequenced manner which is explicitly UB according to [intro.execution]/15. – eerorika Feb 05 '16 at 12:35
  • I'm wrestling with this too, over lunch. – Bathsheba Feb 05 '16 at 12:35
  • 1
    Yeah, it's UB, you shouldn't pay attention to me before I've had coffee (or after, perhaps). – TartanLlama Feb 05 '16 at 12:36
  • BTW, why do you assume C++03? By now, I'm assuming C++>=11 unless specified otherwise. Do you think that's not the more common option on here? – BoBTFish Feb 05 '16 at 12:38
  • 3
    @BoBTFish: pick a random C++ project chosen uniformly from all the still-maintained projects by any corporation in the world, the chance that it's C++>=11 is probably still less than 10% (probably considerably less). – Matteo Italia Feb 05 '16 at 12:39
  • `j` can be const, and there's no point in parenthesising the right-hand side of an assignment. I know it's habit, but still. :) – unwind Feb 05 '16 at 13:00
  • Note that a) rather than `typeof(i)`, one can just write `auto` (or even better `const auto`); b) `({...})` to create an expression block is a GCC extension, not valid in standard C++. (I still occasionally miss my beloved VALOF from BCPL in 1980) – Martin Bonner supports Monica Mar 22 '18 at 08:53