13
int main() {
    int a = 1;
    int b = 0;

    if (a = b || ++a == 2)
        printf("T: a=%i, b=%i", a, b);
    else
        printf("F: a=%i, b=%i", a, b);

    return 0;
}

Let's take a look at this simple code snippet. Result is: T: a=1, b=0

Why? (note a=b uses assignment operand, not comparison)

What I understand here, is that zero is assigned to a, then a is incremented to 1. 1 is not equal to 2. So result should indeed be a=1, b=0. But why is this condition evaluated to true? Neither of (a=b) or (++a == 2) is true ... What did I miss?

Here is other short program that prints F as expected:

int main() {
    int a = 1;
    int b = 0;

    if (a = b) printf("T"); else printf("F");

    return 0;
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Xorty
  • 18,367
  • 27
  • 104
  • 155

3 Answers3

27

You have confused yourself with misleading spacing.

if (a = b || ++a == 2)

is the same as:

if (a = (b || ((++a) == 2)))

This actually has undefined behavior. Although there is a sequence point between the evaluation of b and the evaluation of ((++a) == 2), there is no sequence point between the implied assignment to a and the other write to a due to the explicit = assignment.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
2

Actually, assignment has the lowest operator precedence so your if statement is equivalent to:

if ( a = ( b || ( ++a == 2 ) ) )

So you're assigning a to 1 but also incrementing it in the same expression. I think that leads to undefined behavior, but the end result is that a is 1 in your compiler.

David Grayson
  • 84,103
  • 24
  • 152
  • 189
0

If you are using GCC or another compiler with similarly useful warnings, turning warnings on would give you a very large hint as to what's gone wrong here. With gcc -Wall:

warning: suggest parentheses around assignment used as truth value

To be precise: the compiler is interpreting the code as if (a = (b || ++a == 2)), and the warning is suggesting that you write it as if ((a = (b || ++a == 2))) to emphasize that the code is as intended, not a typo for the more common if (a == (b || ++a == 2)).

So the warning requires a bit of interpretation. To get your desired effect, coincidentally enough you need to add parentheses around a different assignment used as a truth value, namely (a = b). Nonetheless the warning tells you that something is untoward about this particular line of code and that it deserves further scrutiny.

John Marshall
  • 6,815
  • 1
  • 28
  • 38
  • With recent GCC, there's also a warning about the resulting sequence point-related undefined behaviour. This is another large red flag, as in the intended parsing there are clearly no sequence point issues. – John Marshall Jan 07 '12 at 22:07