-3

If x is 0, 0 is printed. If y is 0, we get an error.

Why is this? The only thing I can think of is that the order in which the Boolean expression is compiled matters. If x is 0 then we get (false)&&(error value) where false is on the left side, and if y is 0 then we get (error value)&&(false). Why does this effect what is printed?

int main(void) {
  int x = 1;
  int y = 0;
  int a = (x/y > 0)&&(y/x > 0);
  printf("%d\n", a);
  return 0;
}
  • 3
    Divide by zero should trigger SIGFPE. – llllllllll Mar 02 '18 at 07:41
  • 2
    @liliscent: Not with integer division. – Bathsheba Mar 02 '18 at 07:47
  • 2
    It x is zero the expression is zero and && "short circuit". If y is 0 you divide by zero and invoke undefined behavior. There's nothing more to it. – Lundin Mar 02 '18 at 07:47
  • 2
    @Bathsheba SIGFPE is also raised for integer arithmetic errors. – Max Vollmer Mar 02 '18 at 07:49
  • 1
    @Bathsheba SIGFPE is more inclusive than floating point arithmetic. Even integer division overflow is also SIGFPE. – llllllllll Mar 02 '18 at 07:52
  • 1
    Actually, one of the few ways to get SIGFPE is integer division by zero. Floating point division by zero usually yields an infinity as the result. – Jonathan Leffler Mar 02 '18 at 07:53
  • @JonathanLeffler: But this doesn't fit with the observed behaviour, at least here. I can only think that the compiler is optimising out the expression. – Bathsheba Mar 02 '18 at 07:54
  • @Bathsheba How so? OP said "If y is 0, we get an error." Why do you assume this error isn't a SIGFPE? – Max Vollmer Mar 02 '18 at 07:56
  • In the shown code, `x/y` is undefined behaviour, so the compiler can do what it pleases because `y` is known (at compile time) to be `0`. ([C11 §6.5.5 Multiplicative operators ¶5](http://port70.net/~nsz/c/c11/n1570.html#6.5.5p5).) – Jonathan Leffler Mar 02 '18 at 07:57

2 Answers2

6

In contrast to most other operators in C, operator && defines the order of evaluation from left to right in a "short-curcuit"-manner. I.e., if the first condition fails, the second one will NOT even get evaluated, and it will therefore get no chance to fail. Note that this "short-circuit" evaluation is not just an (optional) optimisation issue; it's guaranteed by the language. So the following expression will never lead to an error:

int x = 1,  y = 0;
int result = (y/x) && (x/y); // OK; y/x yields 0 (meaning false), such that the second operand will not be evaluated.

BTW: operator || also guarantees this short circuit behaviour.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • 2
    This is tagged C. Though in this case the languages are identical. – Lundin Mar 02 '18 at 07:48
  • That's true, but I believe the error, with `y = 0` is in the first operand of the logical operation. I should add that also the logical OR `||` exhibits the same kind of behavior – Stefano Buora Mar 02 '18 at 07:49
  • @Stefano Buora: OP states "either `(false)&&(error value)` or `(error value)&&(false)`", which shows that its either `x=0;y=1` or `x=1;y=0`, but not `x=0;y=0`. – Stephan Lechner Mar 02 '18 at 07:57
2

The behaviour of x / y is undefined as y is 0.

The compiler knows that y is 0 and is clearly optimising out the expression. It also knows that (y/x > 0) is 0, and because of &&, the result of the whole expression is 0.

A less aggressive optimising compiler would raise a division by zero error at runtine. Suggest you check the assembly to see what the compiler has done.

Final Score: Compiler 1, Programmer 0.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • @Downvoter: what have I missed? I can't see any other explanation. – Bathsheba Mar 02 '18 at 07:49
  • I'm not the downvoter, but as I believe you pointed correctly to the problem, your description about the compiler error, runtime error or even SIGFPE as reported in a comment should be improved. – Stefano Buora Mar 02 '18 at 07:51
  • @StefanoBuora: There's no harm in downvoting - it helps folk get answers right. I've added in some blurb. – Bathsheba Mar 02 '18 at 07:53
  • OP said "If y is 0, we get an error." Your answer "A less aggressive compiler would raise a division by zero error at runti[m]e." doesn't fit that description. – Max Vollmer Mar 02 '18 at 07:53
  • 1
    Also your answer doesn't answer OPs question, which is "Why does the order of elements in a Boolean expression change the outcome?" and not "Why does deviding by zero give an error?". This might be an interesting additional information, but it's lacking the explanation for the `&&` operator, that for example Stephan Lechners answer gives. That's why I downvoted, a) your assumption that there is no error even though OP clearly stated there is, and b) not addressing OPs question at all. – Max Vollmer Mar 02 '18 at 08:04
  • 2
    @MaxVollmer: Fair play. I think though that many answers in the future are going to take this form, as compiler optimisations become more aggressive. I didn't consider it very relevant to wax lyrical on the short circuiting and sequencing properties of `&&` since, once UB is encountered, all bets are off. – Bathsheba Mar 02 '18 at 09:10
  • Fair enough, but I think it's still important to give someone who's new and inexperienced the full picture. OP clearly is confused about how `&&` works, and telling them the behavior they see is due to some compiler optimization, without addressing the `&&` operator at all, might leave them in the wrong belief that the `&&` operator evaluates both statements in a situation where the operands are both valid and the left operand is `false`. – Max Vollmer Mar 02 '18 at 09:25
  • 1
    @MaxVollmer: Perhaps you could answer. Combine the (IMHO out of focus) answer of Stephan and parts of mine. I'd upvote that. Note that answers don't necessarily need to be useful to the OP - this is not a forum. If you want to do that, let me know and I'll reopen - for me the duplicate isn't particularly exact despite it being possible to glean an answer from both duplicates. – Bathsheba Mar 02 '18 at 09:27