3

I've been studying C for about a year now, and I came across this above when I was just playing around. I first thought maybe it's a case of assignment precedence (i.e. x=10 happens first), but then I tried

printf("%d %d %d", x==5, x=10, x<6);

and it outputs 0 10 1. Could someone please explain to me why/what is going, as this seems extremely baffling to me and I'm starting to think it's undefined behavior perhaps?

User
  • 55
  • 2
  • 6
    It's undefined behaviour; any result is possible, and that one is as acceptable as any other. – Jonathan Leffler May 11 '19 at 00:24
  • Why is it undefined behavior, is it because I'm assigning within printf? – User May 11 '19 at 00:25
  • 7
    Yes; the order in which the arguments are evaluated is not specified (it's not even implementation defined), and you attempt to change the value of `x` as well as using the value in comparisons while the argument list is evaluated, so the behaviour is undefined. It's a minor variation on the `printf("%d %d %d\n", x--, x, ++x);` type of statement — which is also undefined behaviour with any result being acceptable. – Jonathan Leffler May 11 '19 at 00:27
  • @DavidC.Rankin: C11 [§6.5.2.2 Function calls ¶10](http://port70.net/~nsz/c/c11/n1570.html#6.5.2.2p10): _There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call. Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.94)._ Footnote 94 says: _In other words, function executions do not ''interleave'' with each other._ – Jonathan Leffler May 11 '19 at 00:37
  • That's the one! – David C. Rankin May 11 '19 at 00:39
  • Also C11 [§6.5 Expressions ¶2](http://port70.net/~nsz/c/c11/n1570.html#6.5p2): _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)_ Footnote 84 shows examples of undefined behaviour: `i = ++i + 1;` and `a[i++] = i;`. – Jonathan Leffler May 11 '19 at 00:49

1 Answers1

2

This is indeed undefined behavior. Arguments to functions are evaluated in an unspecified order, so doing anything that relies on that order becomes UB.

It looks like your compiler goes right-to-left (at least in this instance). That's a reasonable way to do it. But since it's UB, don't count on it always doing that.

Draconis
  • 3,209
  • 1
  • 19
  • 31
  • 5
    Dependence on unsequenced evaluations is not always undefined behavior. – Eric Postpischil May 11 '19 at 00:58
  • 2
    “Unspecified order” is imprecise. This answer should say that evaluation of function arguments is “unsequenced.” C has two types of incomplete sequencing: unsequenced and indeterminately sequenced. In unsequenced evaluations, parts of the evaluations can interleave. In indeterminately sequenced evaluations, the evaluations can be in any order but cannot interleave. The rule that causes side effects to have undefined behavior applies only to unsequenced evaluations. – Eric Postpischil May 11 '19 at 01:03
  • @EricPostpischil That's a much better answer; I'm afraid my knowledge of UB doesn't go that deep (I just know "don't depend on order of function operand evaluation") – Draconis May 11 '19 at 01:21
  • You're failing to distinguish between *unspecified behaviour* and *undefined behaviour* – M.M May 11 '19 at 03:58
  • @M.M Isn't this case specifically undefined behavior though, as opposed to unspecified? – Draconis May 11 '19 at 04:11
  • @Draconis It is, but your answer suggests that it is UB because the code relies on the function argument evaluation order (which is not true per se, it is UB due to unsequenced read/write). There can be code that gives different results depending on that order but is not UB. – M.M May 11 '19 at 04:22
  • 1
    @M.M: Yup. For example, `f1(f2(),f3())` may execute `f2()` and then `f3()`, or may execute `f3()` and then `f2()`, but if neither evaluation order would invoke UB, the expression as a whole won't either. – supercat May 11 '19 at 23:14