0

I am curious about the exact definition of the C standard about variable assignment within a conditional clause. Here is a small example:

int foo() {
  ...
}

int bar() {
  ...
}

int main () {
  int a, b, x, y;
  ...
  if ( (a = foo()) == x && (b = bar() == y ) {
    ...
  }
  ...
}

A test with GCC revealed that if (a = foo()) != x, b = bar() will not be executed. On the one hand this behavior is optimal, as it will not waste any time with the calculation of bar(). On the other hand, though, the value of b is somewhat undefined, because it depends on the result of foo(), which actually has nothing to do with b.

I wonder if there is an explicit definition for such cases in the C standard and what the reasons for that definition would be. And finally, what is considered to be best practice for writing such code?

Thargon
  • 424
  • 1
  • 3
  • 12
  • 4
    Look up "short circuit evaluation" – Mat Oct 13 '17 at 09:26
  • Which cases? Please elaborate. – Sourav Ghosh Oct 13 '17 at 09:27
  • If the code after the `if` depends on `b` being initialized, then the "best practice" is to not do like that. – Some programmer dude Oct 13 '17 at 09:27
  • 1
    Match brackets please. – Gnqz Oct 13 '17 at 09:28
  • 1
    Some flavour of this question has been asked a 100 times before on SO. Please do some research before posting. To the people who answered anyway, please close vote instead, a list of canonical dupes can be found in the [SO C tag wiki FAQ](https://stackoverflow.com/tags/c/info). – Lundin Oct 13 '17 at 09:33
  • Short-circuiting of `&&` and `||` is very common in computer languages in general, and is well-documented behavior in C. In fact, in `a && b`, the compiler is *forbidden* from evaluating `b` if `a` is false (at least, insofar as observable side-effects are concerned). This is something beginning C programmers typically learn in their first week of coding in C. – Tom Karzes Oct 13 '17 at 09:34

3 Answers3

0

It's very simple: the second (i.e. right hand) argument of && will not be evaluated if the first argument evaluates to 0.

So, (b = bar() == y ) will not be evaluated if (a = foo()) == x is 0.

The fact that this could leave b uninitialised - with potentially undefined results - is a touchstone for the fact that you ought not code this way.

You could use

if ((a = foo() == x) & (b = bar() == y))

if you want both sides to always be evaluated: & is not short-circuited. But beware of unexpected effects if the arguments can evaluate to something other than 0 or 1 (which they don't in this case).

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

A test with GCC revealed that if (a = foo()) != x, b = bar() will not be executed.

Well, that's the property of the logical AND (&&) operator.

Quoting C11, chapter §6.5.13, emphasis mine

Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares equal to 0, the second operand is not evaluated.

That said, for the assignment of b, you're right, if the first operand is FALSE, the value of b remains indeterminate and any usage of the variable may lead to undefined behavior.

(One of the) The best practice, is to initialize local variables upon definition to avoid use of indeterminate value.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0

The operator && consists of short circuit evaluation: the second subexpression is only evaluated if its result is needed in order to determine the result of the whole expression.


In your example, in the expression:

(a = foo()) == x && (b = bar() == y)

if the first subexpression (a = foo()) == x is evaluated to false, the result of the expression above is also false regardless of the result that the subexpression (b = bar() == y) would produce.

Because of both short-circuit evaluation and the fact that (a = foo()) == x evaluates to false, the expression (b = bar() == y) is never evaluated.

JFMR
  • 23,265
  • 4
  • 52
  • 76