5

I am doing review questions which ask me "What is the output of the following," and I am having some trouble understanding something about this function:

int a = 1, b = 1, c = -1;
c = --a && b++;
printf("%d %d %d", a, b, c);

The output is 010. My question is about line 2, c = --a && b++. How is this line processed, and how does it work/change the values? And if it were c = --a || b++? From my understanding I thought the output would be 020.

Schwern
  • 153,029
  • 25
  • 195
  • 336
Bobbis
  • 137
  • 1
  • 7
  • Learn about pre and post in/decreament operator properties. – Sourav Ghosh Apr 22 '16 at 08:04
  • 1
    Before you add an answer, note that `--a && b++` short circuits. – Schwern Apr 22 '16 at 08:14
  • Possible duplicate of [Is short-circuiting logical operators mandated? And evaluation order?](https://stackoverflow.com/questions/628526/is-short-circuiting-logical-operators-mandated-and-evaluation-order) – phuclv Aug 18 '18 at 14:51

7 Answers7

12

The key concept to understanding the result is short-circuit evaluation of Boolean operators (&& and ||) -- if, after evaluating the left-hand side of a Boolean operator, the value of the right-hand side cannot affect the overall result, then it will not be evaluated and any side-effects it would produce will not happen.

In the first case, since --a evaluates to 0 (=false) the second part of ... && ... is not evaluated, since "false AND anything" will always be false. Specifically, b++ is never executed, and so its value remains 1 in the output.

In the case of --a || b++, the value of the whole expression cannot be determined by the left-hand side ("false OR something" can still be true) so the b++ is evaluated (and it's side-effect, incrementing b, happens).

The other concept needed to fully understand the results is the difference between pre- and post-increment/decrement operators. If the -- or ++ appears before the variable (as in --a) then the variable is decremented or incremented first and new value is used to evaluate the whole expression. If the -- or ++ appears after the variable (as in b++) then the current value of the variable is used to evaluate the expression and the increment/decrement happens after this has happened.

It should be noted that expressions that try to combine two or more instances of --/++ of the same variable (e.g. a++ + ++a) are quite likely to invoke undefined behaviour -- the result may vary by platform, compiler, compiler and even the time of day.

TripeHound
  • 2,721
  • 23
  • 37
6

In the expression c = --a && b++, a gets decreased and returned. Now the second argument of the expression --a && b++ is not evaluated because of short circuit evaluation---once we see that --a==0 we already know that the expression will be 0 regardless of what is the other argument---, so b remains unchanged.

Decreased a is 0 and b remains 1.

The output is, as you suggest, 0 1 0.

Regarding the second question, if you write c = --a || b++, the variable a again goes to zero but the expression can still evaluate to true---we must thus evaluate the second part as well, thus executing b++ which returns 1 and increases b. In this case the output would be 0 2 1, because c is assigned the value of 0 || 1 which is 1.

In short, read up on

Community
  • 1
  • 1
blazs
  • 4,705
  • 24
  • 38
  • Yeah, because of [short circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation); I updated the answer – blazs Apr 22 '16 at 08:11
  • 1
    The missing piece is `--a && b++` short circuits. `--a` is false so `b++` is never executed. – Schwern Apr 22 '16 at 08:11
3

The thing you need to focus on here first is the properties of prefix and postfix operators and their differences.

  • For Postfix increment and decrement operators, C11, chapter §6.5.2.4, (emphasis mine)

    The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented [...] The postfix -- operator is analogous to the postfix ++ operator, except that the value of the operand is decremented.

  • For Prefix increment and decrement operators, C11, chapter §6.5.3.1, (emphasis mine)

    The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. [...] The prefix -- operator is analogous to the prefix ++ operator, except that the value of the operand is decremented.

Now, there comes the property of the Logical AND (&&) operator. From chapter §6.5.13, (again, emphasis mine)

the && operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares equal to 0, the second operand is not evaluated. [...]

So, in your case,

int a = 1, b = 1, c = -1;
c = --a && b++;

gets evaluated as

c = 0 && .....; // done..., a is decremented to 0, 
                //            so, LHS of && is 0, RHS is not evaluated,
                //            b remains 1
                //            and finally, C gets 0.

On the other hand, if logical OR (||) would have been used, then, as per the property, mentioned in chapter §6.5.14

[...] the || operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares unequal to 0, the second operand is not evaluated.

So, for the case

int a = 1, b = 1, c = -1;
c = --a || b++;

it will be evaluated as

c = 0 || 1;   //yes, b's value will be used, and then incremented.

So,

printf("%d %d %d", a, b, c);

will be

0 2 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1

The line :

c = --a && b++;

decreases a to 0, so the statement 0 && anything else results to 0. This is why a and c result to 0, as it seems you have understood.

Now let's see the part you don't get. When a is evaluated to 0, the right part of && does not need to be evaluated, as no matter what the value of the right part will be calculated to be, the result will be 0. This means that b++ will not be evaluated and therefore b will retain its initial value. This is why you see the value 1 instead of 2, and consequently the output 0 1 0 instead of 0 2 0.

Marievi
  • 4,951
  • 1
  • 16
  • 33
1
c = --a && b++;

In this first --a is evaulated and a becomes 0 , as soon as 1 operand of && is false , b++ is not evaluated , therefore ,b remains 1 and c becomes 0.

ameyCU
  • 16,489
  • 2
  • 26
  • 41
1

b++ is simply never executed because --a evaluates to false in an and condition. The right side of the and is never executed because not needed. Hence b is never incremented and hence the output you did not expect.

Philip Stuyck
  • 7,344
  • 3
  • 28
  • 39
-2

--a : mean you decrease a before do the line. b++: increase b after do the line. so that c ( at that time ) = 0+1 =1; then: a =0, b = 2, c =1; OK

chickensoup
  • 334
  • 1
  • 17