Question

I'm currently learning C, and my teacher gave us some homework. We had to identify the output of some code. I don't understand how y=4.

The code is as follows

int main() {

    int w = 3, y = 3;
    printf("w = %i\n", --w + w--);
    printf("y = %i\n\n", y = w + y++);

    return 0;
}
Was it helpful?

Solution 2

Let me preface this with an important public service announcement:

When your compiler gives you a warning, any warning, you would do well to pay attention to it. The code example in your question gives rise to Undefined Behavior - in other words, the C standard does not guarantee that every compiler will give the same results, given your code. That is Always a Bad Thing.

With that out of the way, here is an explanation of what is going on.

I modified your code slightly to look at the intermediate value of w:

#include <stdio.h>

int main(void) {

    int w = 3, y = 3;
    printf("w = %i\n", --w + w--);
    printf("w is actually %d\n", w);
    printf("y = %i\n\n", y = w + y++);

    return 0;
}

My compiler complains about this code with the following warnings:

order.c:6:24: warning: multiple unsequenced modifications to 'w' [-Wunsequenced]
    printf("w = %i\n", --w + w--);
                       ^      ~~
order.c:8:35: warning: multiple unsequenced modifications to 'y' [-Wunsequenced]
    printf("y = %i\n\n", y = w + y++);
                           ~      ^
2 warnings generated.

And the output is

w = 4
w is actually 1
y = 4

What is happening? Since compilers parse the statement left-to-right, the statement

--w + w--

seems to result in the following steps (for my compiler):

--w  : decrement w, it is now 2
w--  : use the value of '2', but decrement w when you are done

The result is that the sum is 2+2 and the first line prints 4, but after the sum is evaluated w is decremented to 1. However you cannot rely on this behavior - which is why the compiler threw a warning. As Eric Postpischil pointed out there may be situations where the order of execution might be different. "Don't do it" is the bottom line - you are courting Undefined Behavior.

Note that the fact that your program printed w equals 4 doesn't mean that this was true at any time. As you can see, when you actually print out w it is 1.

Assuming the compiler executed these statements in the above order, we go to the next line:

y = w + y++

We start with w = 1 and y = 3. The sum of these two is 4, and that is the value of the expression

y = w + y++

which is therefore what is printed (4).

As a side effect, y is incremented. As it happens, either way the value of y is 4 at the end. If you change the code so you start with w = 5, you end up with y = 6. In other words, the effect of y++ got overridden by the y = assignment.

OTHER TIPS

The behaviour is undefined since you modify the value of a variable twice between two sequence points.

You should read more about sequence points http://en.wikipedia.org/wiki/Sequence_point .This is what the Standard says about it:

At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.

Undefined Behavior

There is undefined behavior (as described in Why are these constructs (using ++) undefined behavior?) in this code in (at least) these two parts:

--w + w--

y = w + y++

This means that the results you're getting aren't portable or guaranteed.

Lying Code

On top of the undefined behavior, the output actually lies to you. printf("w = %i\n", --w + w--); looks like it's printing the value of w (in that it prints w = …), but it's not printing the value of w, it's printing the value of --w + w-- (which is undefined, so it's actually printing the value of whatever the compiler compiled --w + w-- to).

So what the value of w?

The code your compiler has generated for --w + w-- has the side effect of making w's value be 1, since it is originally 3, and both --w and w-- decrement w. However, the value of --w + w-- (in the code that your compiler generated is, based on the output that you're getting, 4. What could cause this? Well, --w could be evaluated first, which decrements w from 3 to 2, and returns the new value of w, which is 2. Then w-- could be evaluated, which decrements w from 2 to 1, but returns the original value of w, which is 2. The sum of 2 and 2, of course, is 4.

So, the value of --w + w-- is 4, and the new value of w is 1.

And what happens with y?

w's new value is 1, so when you execute (recalling that the value of y is 3):

printf("y = %i\n\n", y = w + y++);

The side effect of y++ is that y is incremented (but it's undefined whether this happens before or after the assignment), but the value of the expression is the previous value of y, which in this case is 3. Therefore, you're adding w, whose value is 1, and and the value of y++, which is 3. You're then assigning 4 to y, and the value of that assignment is 4, so you get 4 as the output. There's still behavior that might be undefined in y = w + y++ because it's not clear when the increment of y should be happening: before or after the assignment?

Your teacher is assuming a specific order of evaluation which is not guaranteed by the language.

Assuming strict left-to-right evaluation, and assuming that side effects are applied immediately, then given the starting values for w and y, the following things happen:

  1. --w evaluates to w-1 (2), and as a side effect decrements w; w is now 2
  2. w-- evaluates to w (2), and as a side effect decrements w; w is now 1
  3. As a result of 1 and 2, --w + w-- evaluates to 4
  4. y++ evaluates to y, and as a side effect increments y; y is now 4
  5. As a result of 4, w + y++ evaluates to 1 + 3, or 4
  6. As a result of 5, y = w + y++ assigns 4 to y.

BUT...

As I said above, this behavior is not guaranteed by the language; except in a few specific cases, the order of evaluation within an expression is left unspecified, so y being 4 is only one of many possible results, all of which are considered equally correct as far as the langauge is concerned.

The behavior of any expression that takes on the following forms (both ++ and --, both prefix and postfix):

x++ + x++   
a[i++] = i
y = y++

is undefined. Similarly, the behavior of statments like

foo(y++, y++);

is also undefined.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top