-1

In the code below, according to me, the output should be 11 6 10, but it gives 12 6 11. The value of k=x as returned by the ternary operator since x>y where x=10 and y=6, so i=11, j=6 and k=10, so why is there a mismatch in the output produced?

#include <stdio.h>

#define MAX(x,y)(x)>(y)?(x):(y)

int main()
{
    int i=10,j=5,k=0;
    k=MAX(i++,++j);
    printf("%d %d %d",i,j,k);
    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user94
  • 25
  • 3

2 Answers2

2

The expansion is equivalent to:

k = (i++) > (++j) ? (i++) : (++j);

Both i and j are incremented as the condition is evaluated (so i becomes 11 and j becomes 6. Since the condition checks the original value of i and the incremented value of j and 10 > 6, the i++ after the ? is evaluated, so k is assigned 11 and i is incremented to 12.

Hence the output is, as it should be:

12 6 11

There is no undefined behaviour here. There's a full sequence point after the condition is evaluated.

Note, too, that for full safety, the macro should have an extra set of parentheses around the expansion:

#define MAX(x,y)  ((x) > (y) ? (x) : (y))

Otherwise, you get odd-ball effects from:

int l = 7 * MAX(k, i) + 3;

It works; it just doesn't work as expected.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • `(i++) > (++j)` is this guaranteed that both `i` and `j` are incremented after the comparison? (and before the `?`) – artm Jul 24 '16 at 06:48
  • Yes; both `i` and `j` are incremented when the comparison is complete and before either of the terms after the question mark is evaluated. – Jonathan Leffler Jul 24 '16 at 06:49
  • so in this particular case, it's the same as writing `(++i) > (++j) ? (++i) : (++j);` ? – artm Jul 24 '16 at 06:50
  • No; because in your rewrite, the value assigned to `k` would be 12, not 11, because of the preincrement of `i` after the `?`. Also, with other values for `i` and `j` (such as `i = 6` and `j = 5`), the comparisons `(i++) > (++j)` and `(++i) > (++j)` would evaluate differently. – Jonathan Leffler Jul 24 '16 at 06:51
  • ok thanks for the explaination – artm Jul 24 '16 at 06:53
1

The output works as expected. You'll need to understand macros are expanded, and do not work like functions where the input parameters are copied.

The definition of MAX in the above code is

#define MAX(x, y) (x)>(y)?(x):(y)

So

k = MAX(i++, ++j)

expands to

k = (i++)>(++j)?(i++):(++j)

The variable i gets incremented twice when i=10 and j=5. The variable j gets incremented only once.

So eventually i=12 and j=6, and k=11 because the second operand in the ternary operator is a post-increment.

If you are using gcc, running cpp instead of gcc on the .c file would expand the macro nicely for you.

Apart from Jonathan Leffler's comment on using more parentheses in the macro for safety, you can consider using inline functions that could save you from these unintended results. Inline functions have the benefits of being typed, passing-by-value, and code expansion.

inline int max(int x, int y) { return x > y ? x : y; }

See the wiki for more details.

Wai Leong
  • 328
  • 2
  • 7