Why does a=(b++) have the same behavior as a=b++?

前端 未结 10 2048
借酒劲吻你
借酒劲吻你 2020-12-06 16:14

I am writing a small test app in C with GCC 4.8.4 pre-installed on my Ubuntu 14.04. And I got confused for the fact that the expression a=(b++); behaves in the

相关标签:
10条回答
  • 2020-12-06 17:02

    To make it short: b++ is incremented after the statement is done

    But even after that, the result of b++ is put to a.

    Because of that parentheses do not change the value here.

    0 讨论(0)
  • 2020-12-06 17:04

    Parentheses can be tricky to think about. But they do not mean, "make sure that everything inside happens first".

    Suppose we have

    a = b + c * d;
    

    The higher precedence of multiplication over addition tells us that the compiler will arrange to multiply c by d, and then add the result to b. If we want the other interpretation, we can use parentheses:

    a = (b + c) * d;
    

    But suppose that we have some function calls thrown into the mix. That is, suppose we write

     a = x() + y() * z();
    

    Now, while it's clear that the return value of y() will be multiplied by the return value of z(), can we say anything about the order that x(), y(), and z() will be called in? The answer is, no, we absolutely cannot! If you're at all unsure, I invite you to try it, using x, y, and z functions like this:

    int x() { printf("this is x()\n"); return 2; }
    int y() { printf("this is y()\n"); return 3; }
    int z() { printf("this is z()\n"); return 4; }
    

    The first time I tried this, using the compiler in front of me, I discovered that function x() was called first, even though its result is needed last. When I changed the calling code to

     a = (x() + y()) * z();
    

    the order of the calls to x, y, and z stayed exactly the same, the compiler just arranged to combine their results differently.

    Finally, it's important to realize that expressions like i++ do two things: they take i's value and add 1 to it, and then they store the new value back into i. But the store back into i doesn't necessarily happen right away, it can happen later. And the question of "when exactly does the store back into i happen?" is sort of like the question of "when does function x get called?". You can't really tell, it's up to the compiler, it usually doesn't matter, it will differ from compiler to compiler, if you really care, you're going to have to do something else to force the order.

    And in any case, remember that the definition of i++ is that it gives the old value of i out to the surrounding expression. That's a pretty absolute rule, and it can not be changed just by adding some parentheses! That's not what parentheses do.

    Let's go back to the previous example involving functions x, y, and z. I noticed that function x was called first. Suppose I didn't want that, suppose I wanted functions y and z to be called first. Could I achieve that by writing

    x = z() + ((y() * z())?
    

    I could write that, but it doesn't change anything. Remember, the parentheses don't mean "do everything inside first". They do cause the multiplication to happen before the addition, but the compiler was already going to do it that way anyway, based on the higher precedence of multiplication over addition.

    Up above I said, "if you really care, you're going to have to do something else to force the order". What you generally have to do is use some temporary variables and some extra statements. (The technical term is "insert some sequence points.") For example, to cause y and z to get called first, I could write

    c = y();
    d = z();
    b = x();
    a = b + c * d;
    

    In your case, if you wanted to make sure that the new value of b got assigned to a, you could write

    c = b++;
    a = b;
    

    But of course that's silly -- if all you want to do is increment b and have its new value assigned to a, that's what prefix ++ is for:

    a = ++b;
    
    0 讨论(0)
  • 2020-12-06 17:07

    Parentheses are entirely syntactic. They just group expressions and they are useful if you want to override the precedence or associativity of operators. For example, if you use parentheses here:

    a = 2*(b+1);
    

    you mean that the result of b+1 should be doubled, whereas if you omit the parentheses:

    a = 2*b+1;
    

    you mean that just b should be doubled and then the result should be incremented. The two syntax trees for these assignments are:

       =                      =
      / \                    / \
     a   *                  a   +
        / \                    / \
       2   +                  *   1
          / \                / \
         b   1              2   b
    
    a = 2*(b+1);            a = 2*b+1;
    

    By using parentheses, you can therefore change the syntax tree that corresponds to your program and (of course) different syntax may correspond to different semantics.

    On the other hand, in your program:

    a1 = (b1++);
    a2 = b2++;
    

    parentheses are redundant because the assignment operator has lower precedence than the postfix increment (++). The two assignments are equivalent; in both cases, the corresponding syntax tree is the following:

        =
       / \
      a   ++ (postfix)
          |
          b
    

    Now that we're done with the syntax, let's go to semantics. This statement means: evaluate b++ and assign the result to a. Evaluating b++ returns the current value of b (which is 10 in your program) and, as a side effect, increments b (which now becomes 11). The returned value (that is, 10) is assigned to a. This is what you observe, and this is the correct behaviour.

    0 讨论(0)
  • 2020-12-06 17:07

    Placing ++ at the end of a statement (known as post-increment), means that the increment is to be done after the statement.

    Even enclosing the variable in parenthesis doesn't change the fact that it will be incremented after the statement is done.

    From learn.geekinterview.com:

    In the postfix form, the increment or decrement takes place after the value is used in expression evaluation.

    In prefix increment or decrement operation the increment or decrement takes place before the value is used in expression evaluation.

    That's why a = (b++) and a = b++ are the same in terms of behavior.

    In your case, if you want to increment b first, you should use pre-increment, ++b instead of b++ or (b++).

    Change

    a1 = (b1++);
    

    to

    a1 = ++b1; // b will be incremented before it is assigned to a.
    
    0 讨论(0)
提交回复
热议问题