18
votes

OK, I'm a little embarassed to ask this question, but I just want to be sure...

It is known that C uses short circuit evaluation in boolean expressions:

int c = 0;
if (c && func(c)) { /* whatever... */ }

In that example func(c) is not called because c evaluates to 0. But how about more sophisticated example where side effects of comparison would change the variable being compared next? Like this:

int c; /* this is not even initialized... */
if (canInitWithSomeValue(&c) && c == SOMETHING) { /*...*/ }

Function canInitWithSomeValue returns true and changes value at given pointer in case of success. Is it guaranteed that subsequent comparisons (c == SOMETHING in this example) uses value set by canInitWithSomeValue(&c)?

No matter how heavy optimizations the compiler uses?

3
I think you may be confusing short circuit evaluation and compiler optimisation. In the first example, the compiler will optimise away that entire if statement, because it can never run. Short circuit-evaluation would mean that if you had if(func1() && func2()) { ... }, and func1() evaluated to false at runtime (i.e. not definetely when compiling), then the code should not check func2() - the compiler should have crafted the machine code such that if func1() is false, func2() isn't called. - Stephen
That int c = 0 was there to indicate that c is equal to 0 at the time of comparision, I realize that in a case that simple the compiler would optimise the entire if. - Łukasz Sromek
Ah, I do apologise. I misread you. My apologies. - Stephen

3 Answers

24
votes

Is it guaranteed that subsequent comparisons (c == SOMETHING in this example) uses value set by canInitWithSomeValue(&c)?

Yes. Because there is a sequence point

Between evaluation of the left and right operands of the && (logical AND), || (logical OR), and comma operators. For example, in the expression *p++ != 0 && *q++ != 0, all side effects of the sub-expression *p++ != 0 are completed before any attempt to access q.


A sequence point defines any point in a computer program's execution at which it is guaranteed that all side effects of previous evaluations will have been performed, and no side effects from subsequent evaluations have yet been performed.

5
votes

Yes. Because both && and || operator are also something called sequence points. The latter define when the side-effects of a previous operation should be complete and those of the next should not have begun.

1
votes

Evaluation within the if statement composite condition is strictly left to right. The only circumstance under which the second test in your if would be optimized out is if the compiler can determine with 100% certainty that the first is identically equal to false.