-3
#include <stdio.h>

int main() {
    int y = 1;
    if (y & (y = 2))
        printf("true %d\n",y);
    else
        printf("false %d\n",y);
    return 0;
}

How does the output come as true 2? According to me inside the if condition this will happen if( 1 & (2)) but the output comes as true 2.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Anuj Singh
  • 1
  • 1
  • 4
  • Binary AND Operator: &, copies a bit to the result if it exists in both operands. – danglingpointer Aug 30 '18 at 12:16
  • 2
    Because there is no fixed ordering between the update to `y` and the read of `y`. Thus you have invoked what is called Undefined Behavior. The behavior of the program from this point onwards cannot be argued about at all. – Ajay Brahmakshatriya Aug 30 '18 at 12:17
  • What is the purpose of the condition? What are you really trying to do? What is the *actual problem* you try to solve? – Some programmer dude Aug 30 '18 at 12:29
  • 2
    I don't think we need yet another "obscure expressions and sequence points" debate, there's already 1000+ questions like this on the site. The linked duplicates are close enough, but if anyone got a better please link it. – Lundin Aug 30 '18 at 12:33
  • @Lundin maybe, but it has 4 upvoted answers:(( – Martin James Aug 30 '18 at 15:33

4 Answers4

4

In the expression y&(y=2) you are both reading and writing y without an sequence point between them. Doing so invokes undefined behavior. This means that the behavior of the program cannot be accurately predicted, so no answer is "correct".

dbush
  • 205,898
  • 23
  • 218
  • 273
3

What you have encountered is a classic case of Undefined Behavior. The C standard does not impose any order the evaluation of subexpressions of &. Thus there is no way to know whether y=2 will happen first or y (the read).

This is also called an unsequenced read and write on the same variable.

Because you have invoked UB, you cannot argue anything about the behavior of the program beyond this point.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
2

When you do y=2 you do assignment. You assign the value 2 to y.

Also note that single & is bitwise and, not logical and.

If you want to compare for equality use == as in y == 2.

If you want to use logical and use && as in y && y == 2. Though this is really not needed as y is equivalent to y != 0 and that's already implied in the comparison to 2.


And as noted, because the order of evaluation is not defined, we can't tell if y or y = 2 would happen first, which means that y & (y = 2) is undefined behavior.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 3
  • That's an interesting question. `y&(y=2)` is always true if y was assigned the value 1 previously. – Thomas Jager Aug 30 '18 at 12:18
  • @AjayBrahmakshatriya Never mind, I'm an idiot who can't seem to process what he just read – Thomas Jager Aug 30 '18 at 12:20
  • @AjayBrahmakshatriya Good question. On one hand there's no side-effect of the expression `y`. On the other hand the result of the bitwise and could be different depending on order. So yes I'd say it's UB. – Some programmer dude Aug 30 '18 at 12:21
  • @Someprogrammerdude I see a read an write to the same variable (the write not depending on the read) between two sequence points. That should be enough right? – Ajay Brahmakshatriya Aug 30 '18 at 12:23
  • @ThomasJager Not a problem :) – Ajay Brahmakshatriya Aug 30 '18 at 12:23
  • 1
    *In reality it won't matter much since the full expression still would be non-zero* -- It would not be if the read happens before the write `0b10 & 0b01`. I think this is the behavior OP was originally expecting! – Ajay Brahmakshatriya Aug 30 '18 at 12:25
  • 1=01 and 2=10 and on (01 & 10)=00 which is quivalent to o so how that if condition will become true ? – Anuj Singh Aug 30 '18 at 12:27
  • @Someprogrammerdude Hmmm, Had code been `(void) (y & (y = 2))` where there is a lack of sequence point in `y & (y = 2)`, yet the _result is discarded_, I think the effect is still _undefined behavior_. Just not sure what specifies that. Your thoughts? – chux - Reinstate Monica Aug 30 '18 at 12:43
  • 1
    @chux I'm not really that good with the language-lawyer stuff, but per the specification I think it's still UB. A reasonable compiler should be able to optimize it to just `(void) (y = 2)` though which is just a plain normal assignment like most people do, and that's not UB. – Some programmer dude Aug 30 '18 at 12:52
2

The behaviour of y & (y = 2) is undefined. That's because there is a read and write on y in an unsequenced step.

It would have been a different matter had you written y && (y = 2). && is a sequencing point, although the assignment of 2 to y would only take place if y is non-zero (which it is in your case).

Finally, 1 & 2 is 0, whereas 1 && 2 is 1; a touchstone for those folk who like to force argument evaluation by writing & in place of &&.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483