-3
#include <stdio.h>

int main()
{
    int y = 1;
    if (y & (y = 2))
        printf("true \n");

    else
        printf("false \n");
        return 0;
}

Output:

true

In this program there is an undefined behaviour. The output is always true. I've tried few compilers. Can anyone explain me why it is true all the time?

Pankaj Mahato
  • 1,051
  • 5
  • 14
  • 26
  • you are using bitwise and &, use && for normal "AND operator', also y ==2 if you want to check if its 2. – tesseract Jan 25 '14 at 13:45
  • Also that code won't work since you are not passing printf anything. – edmz Jan 25 '14 at 13:47
  • 4
    Pretty sure the point is (0x01 & 0x02) is *false*, yet all compilers he tries *seem* to eval the parenthetical assignment *first*, resulting in (0x02 & 0x02), which is *true*. I'm quite certain that assignment is no accident, as answers below seems to conclude. (and before anyone asks, I didn't down vote *anyone*). – WhozCraig Jan 25 '14 at 13:49
  • well no down votes should be applied to answers on that "assumption". Pankaj, explain it???? – T McKeown Jan 25 '14 at 13:52
  • When you tried this (and you may do well to cite the "lots of compiler" you used and their modes-of-compilation), did you use any optimization, or was it strictly debug builds? – WhozCraig Jan 25 '14 at 13:58
  • @TMcKeown I did not down vote anything. – Pankaj Mahato Jan 25 '14 at 13:59
  • I want to perform & operation not && operation – Pankaj Mahato Jan 25 '14 at 13:59
  • Sorry, I meant explain your code. – T McKeown Jan 25 '14 at 13:59
  • if it were the brackets. why is it undefined? brackets have the highest precedence so i would expect the y =2 assignment to take place before the bitwise and. I will go with @WhozCraig answer, am i missing something? – tesseract Jan 25 '14 at 14:00
  • 3
    @PankajMahato compiling this on clang 3.5 @ -O3 I receive false, so perhaps vary your test beds a bit. Also, she's smart enough to give me this as well, which I'm guessing you already knew: `warning: unsequenced modification and access to 'y' [-Wunsequenced]` – WhozCraig Jan 25 '14 at 14:01
  • @WhozCraig I didn't use any optimizations – Pankaj Mahato Jan 25 '14 at 14:02
  • 2
    There really isn't a "why" here. Undefined behavior is undefined. – Stephen Canon Jan 25 '14 at 14:08
  • @DCoder: that's an excellent dupe. Thanks for digging it up. – Stephen Canon Jan 25 '14 at 14:21
  • @tesseract `(y = 2)` evaluation needs to be precede `left_arg & right_arg`, That does not prevent `left_arg` evaluation from occurring first. – chux - Reinstate Monica Jan 25 '14 at 14:41

3 Answers3

4

Because observed behavior is not defined behavior. The compilers you're using seem (by observation solely) to be performing the following:

  1. Assign y = 2
  2. Eval result of step (1)
  3. Eval y
  4. Bitwise-AND the results of steps (2) and (3) above.
  5. Eval result from step (4)

The result would be (2 & 2), which is true. The problem is, the order of 1-2, then 3 is not standard-defined. It could just as easily be this:

  1. Eval y
  2. Assign y = 2
  3. Eval result of step (2)
  4. Bitwise-AND the results of steps (1) and (3) above.
  5. Eval result from step (4)

The result would be (1 & 2), which is false

Or it could be something else entirely. Not all compilers will do the first, and you cannot assume because the compilers you used do, they all will. Nor can you assume that because they do and you observed that behavior, it is therefore defined; it isn't. Compilers don't define behavior; the standard does, and compilers are obliged to comply.

Note: there is a loophole in this era of definition, but it is not the norm, and even it is loosely defined by the standard. You will find areas within the standard the say something is "implementation-defined." In such cases the standard points out these areas of divergence with reasonably clarity. In such cases you should consult your implementation for definitive conclusion as to what behavior to expect, and in so doing be prepared to accept the simple a fact that such behavior can only be relied on within the confines of the implementation. This (your sample) is not such loophole exception.

My clang 3.5 rig seems (by my observation) to run the second sequence, not the first, and I could take your road and assume that "all" the compilers I tried (one of them) behave like that, therefore it is defined to be so. I would be mistaken to do so, as are you in your assumption.

Undefined behavior is just that; undefined.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • 3
    I hesitate to drag this out any longer, but it is perhaps worth noting that a compiler may detect that the expression `(y & (y = 2))` is undefined (hence neither true nor false), and optimize the whole thing away. The program may print *nothing at all*. – Stephen Canon Jan 25 '14 at 14:40
  • 3
    @StephenCanon A totally fair point and worthy of the comment-upvote. Or it may decide all UB evals to *false* in my little I-get-to-define-what-UB-is universe. Excellent point. UB, ye art a cruel and heartless wench. – WhozCraig Jan 25 '14 at 14:42
0

You are trying to modify the value of y more than once between sequence points. There is not a standard way on how to handle that behavior. So:

i = i++; // gives undefined behavior also

valter

-2

Yes, the code will always return True Because any non-zero value in any conditional statement is True(C-99 above) or 1(C-99) in C

if (y & (y = 2))
    printf("true %d\n");

In the if condition 2 is assigned to y first and then 2 is bitwise &'ed with 2. i.e. 0010 & 0010 it'll return 0010 as a result.

So now you have:

if(2)  //Any non-zero value is true
    printf("true %d\n");
Saurabh Sharma
  • 2,422
  • 4
  • 20
  • 41
  • 4
    -1; There is no guarantee that it will return true. As the questioner states, the behavior is undefined. There is no ordering on the evaluation of the two operands to `&`. – Stephen Canon Jan 25 '14 at 14:01
  • @StephenCanon Dude, I wish u read the whole question! "The output is always true. I've tried lots of compiler. Can anyone explain me why it is true all the time?" – Saurabh Sharma Jan 25 '14 at 14:03
  • 2
    If you will take the time to read the comments, you will find that it *isn't* true all the time. Even if it were, that would have absolutely no bearing on whether or not the behavior is undefined. – Stephen Canon Jan 25 '14 at 14:04
  • 1
    got false on LLVM version 5 compiler with a warning. warning: unsequenced modification and access to 'y' – tesseract Jan 25 '14 at 14:15
  • 4
    @SaurabhSharma: It is not valid reasoning to deduce from “This has behaved as true in each specific instance I have tested with multiple compilers” that “This is true all the time”. The only way to conclude that “This is true all the time” (where “all the time” is “every standard C implementation” is to deduce it from the rules specified for C in the C standard. The rules of standard C are clear: If you both use an object (`y`) and separately modify it (`y = 2`) in an expression that does not impose an ordering on their evaluation, the behavior is undefined. – Eric Postpischil Jan 25 '14 at 14:16
  • 1
    Your second paragraph *briefly* touches on the undefined behavior in question. You assume that sequence, and it appears the compilers he's trying perform just that. However, there is no defined sequence point in the position you noted, and as such it is UB. Everything else in this answer explains why it results in true, to be sure. This is easily the best answer so far, and if this answer simply said "because the compilers you're using *seem* to do this: blah but they're not *required* to, and some don't" I would up-vote this quickly. – WhozCraig Jan 25 '14 at 14:18