user5055706
user5055706

Reputation: 271

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

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 same way as a=b++; does. The following simple code is used:

#include <stdint.h>
#include <stdio.h>

int main(int argc, char* argv[]){
    uint8_t a1, a2, b1=10, b2=10;
    a1=(b1++);
    a2=b2++;

    printf("a1=%u, a2=%u, b1=%u, b2=%u.\n", a1, a2, b1, b2);

}

The result after gcc compilation is a1=a2=10, while b1=b2=11. However, I expected the parentheses to have b1 incremented before its value is assigned to a1.

Namely, a1 should be 11 while a2 equals 10.

Does anyone get an idea about this issue?

Upvotes: 18

Views: 3770

Answers (10)

Coder55
Coder55

Reputation: 559

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.

Upvotes: 1

syntaxerror
syntaxerror

Reputation: 701

OK, in a nutshell: b++ is a unary expression, and parentheses around it won't ever take influence on precedence of arithmetic operations, because the ++ increment operator has one of the highest (if not the highest) precedence in C. Whilst in a * (b + c), the (b + c) is a binary expression (not to be confused with binary numbering system!) because of a variable b and its addend c. So it can easily be remembered like this: parentheses put around binary, ternary, quaternary...+INF expressions will almost always have influence on precedence(*); parentheses around unary ones NEVER will - because these are "strong enough" to "withstand" grouping by parentheses.

(*)As usual, there are some exceptions to the rule, if only a handful: e. g. -> (to access members of pointers on structures) has a very strong binding despite being a binary operator. However, C beginners are very likely to take quite awhile until they can write a -> in their code, as they will need an advanced understanding of both pointers and structures.

Upvotes: 3

nickie
nickie

Reputation: 5808

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.

Upvotes: 5

raymelfrancisco
raymelfrancisco

Reputation: 871

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.

Upvotes: 1

AnT stands with Russia
AnT stands with Russia

Reputation: 320421

Your expectations are completely unfounded.

Parentheses have no direct effect on the order of execution. They don't introduce sequence points into the expression and thus they don't force any side-effects to materialize earlier than they would've materialized without parentheses.

Moreover, by definition, post-increment expression b++ evaluates to the original value of b. This requirement will remain in place regardless of how many pair of parentheses you add around b++. Even if parentheses somehow "forced" an instant increment, the language would still require (((b++))) to evaluate to the old value of b, meaning that a would still be guaranteed to receive the non-incremented value of b.

Parentheses only affects the syntactic grouping between operators and their operands. For example, in your original expression a = b++ one might immediately ask whether the ++ apples to b alone or to the result of a = b. In your case, by adding the parentheses you simply explicitly forced the ++ operator to apply to (to group with) b operand. However, according to the language syntax (and the operator precedence and associativity derived from it), ++ already applies to b, i.e. unary ++ has higher precedence than binary =. Your parentheses did not change anything, it only reiterated the grouping that was already there implicitly. Hence no change in the behavior.

Upvotes: 6

user1084944
user1084944

Reputation:

However, I expected the parentheses to have b1 incremented before its value is assigned to a1.

You aren't assigning b1 to a1: you're assigning the result of the postincrement expression.

Consider the following program, which prints the value of b when executing assignment:

#include <iostream>
using namespace std;

int b;

struct verbose
{
    int x;

    void operator=(int y) {
        cout << "b is " << b << " when operator= is executed" << endl;  
        x = y;
    }
};

int main() {
    // your code goes here
    verbose a;
    b = 10;
    a = b++;
    cout << "a is " << a.x << endl;
    return 0;
}

I suspect this is undefined behavior, but nonetheless when using ideone.com I get the output shown below

b is 11 when operator= is executed
a is 10

Upvotes: 3

Steve Summit
Steve Summit

Reputation: 47933

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;

Upvotes: 24

askmish
askmish

Reputation: 6674

Quoting from the C99:6.5.2.4:

The result of the postfix ++ operator is the value of the operand. After the result is obtained, the value of the operand is incremented. (That is, the value 1 of the appropriate type is added to it.) See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The side effect of updating the stored value of the operand shall occur between the previous and the next sequence point.

You can look up the C99: annex C to understand what the valid sequence points are.

In your question, just adding a parentheses doesn't change the sequence points, only the ; character does that.

Or in other words, you can view it like there's a temporary copy of b and the side-effect is original b incremented. But, until a sequence point is reached, all evaluation is done on the temporary copy of b. The temporary copy of b is then discarded, the side effect i.e. increment operation is committed to the storage,when a sequence point is reached.

Upvotes: 35

Eric Tsui
Eric Tsui

Reputation: 1924

The parentheses will not change the post-increment behaviour itself.

a1=(b1++); //b1=10

It equals to,

 uint8_t mid_value = b1++; //10
 a1 = (mid_value); //10

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726539

However, I expected the parentheses to have b1 incremented before its value is assigned to a1

You should not have expected that: placing parentheses around an increment expression does not alter the application of its side effects.

Side effects (in this case, it means writing 11 into b1) get applied some time after retrieving the current value of b1. This could happen before or after the full assignment expression is evaluated completely. That is why a post-increment will remain a post-increment, with or without parentheses around it. If you wanted a pre-increment, place ++ before the variable:

a1 = ++b1;

Upvotes: 36

Related Questions