3

what is the difference between i = i + j; and i += j; in C? Are they equivalent? Is there any side effect of i?

I was trying to check the assignment mechanism in C using the GCC compiler.

Mat
  • 202,337
  • 40
  • 393
  • 406
anirban karak
  • 732
  • 7
  • 20
  • Those 2 lines by themselves are the same, no matter the types of I or j. If you added anything else to them within the same statement, then order of precedence could change the resulting answers. That said, I have seen some "not great" compilers output different assembler for them. Go figure :) – Michael Dorgan Jul 16 '13 at 18:05
  • 1
    Check assembly code, you may find interesting details What Carl's answered. – Grijesh Chauhan Jul 16 '13 at 18:11
  • 3
    See http://stackoverflow.com/questions/5031604/is-a-b-more-efficient-than-a-a-b-in-c – makes Jul 16 '13 at 18:18
  • @mizo nice link. What I wanted to post was already there. – Grijesh Chauhan Jul 16 '13 at 18:20
  • This can't really be answered correctly without knowing what `i` and `j` are. One particularly evil example might include `#define i (++j--)` as opposed to a nice clean `int i;`... – twalberg Jul 16 '13 at 19:56

6 Answers6

8

They're almost the same. The only difference is that i is only evaluated once in the += case versus twice in the other case.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • 1
    And `i += j` is more readable :) – VoidPointer Jul 16 '13 at 18:09
  • Would 'i' have to be evaluate twice in the second case and not the first? I'm not quite following your logic here and am interested to hear how you came up with this. – Michael Dorgan Jul 16 '13 at 18:09
  • 5
    @MichaelDorgan Normally it wouldn't matter (and would be optimized out since `i` would be stuffed in some register), but if `i` was volatile and being modified by some other thread or an interrupt, it might be of concern. Hopefully it _still_ wouldn't matter because you've properly ensured [mutual exclusion](http://en.wikipedia.org/wiki/Mutual_exclusion) so that only one unit of execution is accessing it at once. – Matt Kline Jul 16 '13 at 18:12
  • 3
    @MichaelDorgan: It matters when `i` is an expression more complicated than a simple identifier. E.g., `*p(4) = *p(4) + j` must call the function `p` twice (and possibly get different results each time), while `*p(4) += j` only calls `p` once. – Eric Postpischil Jul 16 '13 at 18:16
  • @MichaelDorgan - I didn't really "come up with it", that just happens to be the exact wording of the standard. Eric has a great example. – Carl Norum Jul 16 '13 at 18:17
  • And += forces 'i' to be atomic while the other case does not? That is the part I wonder about. That doesn't quite seem right, but I would love to be proved wrong - Ah Eric's answer makes a lot more sense to me. Thanks - didn't consider a function pointer to code. Nice. – Michael Dorgan Jul 16 '13 at 18:19
  • 1
    No, it doesn't have to be atomic, it just has to be evaluated only a single time. OP didn't say what `i` *is*, so it's hard to be really specific. – Carl Norum Jul 16 '13 at 18:19
5

i = i + j is equivalent to i += j but not same.
In some cases(rare) i += j differs from i = i + j because i itself has a side effect.
Also one more problem is operator precedence i.e

i = i * j + k;

is not same as

i *= j + k;  
haccks
  • 104,019
  • 25
  • 176
  • 264
5

There is almost no difference, but if i is a complex expression, it is only computed once. Suppose you had:

int ia[] = {1, 2, 3, 4, 5};
int *pi = &(ia[0]);  // Yes, I know.  I could just have written pi = ia;
*pi++ += 10;
// ia now is {11, 2, 3, 4, 5}.
// pi now points to ia[1].
// Note this would be undefined behavior:
*pi++ = *pi++ + 10;
Eric Jablow
  • 7,874
  • 2
  • 22
  • 29
2

The two statements i = i + j and i += j, are functionally same, in first case you are using the general assignment operation, while the second one uses the combinatorial assignment operator. += is additive assignment operator (addition followed by assignment). The use of combinatorial assignment operators generates smaller source code that is less susceptible to maintenance errors and also possibly a smaller object code where it would also run faster. Compilation is also likely to be a little faster.

Prashant Chikhalkar
  • 511
  • 1
  • 8
  • 19
1

Syntactic sugar baby.

Any differences are just going to come down to compiler implementation.

http://en.wikipedia.org/wiki/Syntactic_sugar

JonnyRo
  • 1,844
  • 1
  • 14
  • 20
1

In both cases i (the variable or expression being assigned) must be an lvalue. In most simple cases this will yield code that is identical in both cases so long as i is not declared volatile.

However there are a few cases where a lvalue can be an expression involving operators, and this may cause evaluation of i twice. The most plausible example of an lvalue expression that might be used in that way is perhaps simple dereferencing of a pointer (*p):

*p = *p + j ;
*p += j ;

may generate different code, but it is trivially optimised so I would expect not even without optimisation enabled. Again p cannot be volatile, otherwise the expressions are semantically different.

A less plausible scenario is to use a conditional operator expression as an lvalue. For example the following adds j to b or c depending on a:

(a ? b : c) += j ; 
(a ? b : c) = (a ? b : c) + j ;

These might generate different code - the compiler might reasonably not spot that idiom and apply an optimisation. If the expression a has side effects - for example were the expression getchar() == '\n' or a is volatile (regardless of b or c), then they are not equivalent since the second would evaluate to:

  • c = b + j for the input "Y\n",
  • b = b + j for input "\n\n",
  • c = c + j for input "YN".

These points are of course mostly irrelevant - if you write code like that and it does things you did not expect, sympathy may be in short supply!

Clifford
  • 88,407
  • 13
  • 85
  • 165