3

As the title says I found such a sentence in some C lecture notes.

I can't invent any example proving that sentence.

In my opinion every of assignment operations is evaluated once, because when we want it to be evaluated more than once we put in in a loop. What am I missing then?

I've searched but couldn't find an answer here on SO.

Peter Cerba
  • 806
  • 4
  • 14
  • 26
  • No assignment that actually explains the problem, on the contrary to eg. `x += 6` – Peter Cerba Aug 26 '12 at 20:43
  • See [What does the |= operator mean in C++](http://stackoverflow.com/questions/4217762/what-does-the-operator-mean-in-c/4217772#4217772) which, although it is for C++, does explain what it means for the LHS of the operator to be evaluated once. Except for the mention of operator overloading (which is in C++ only), the commentary applies to C and `+=` (and `|=` and the other assignment operators). – Jonathan Leffler Aug 26 '12 at 20:52

6 Answers6

6

C says:

(C99, 6.5.16.2p3) "A compound assignment of the form E1 op= E2 differs from the simple assignment expression E1 = E1 op (E2) only in that the lvalue E1 is evaluated only once."

Below are some examples of why it matters:

Example 1:

 a[i++] += 1;

is the same as:

 a[i] = a[i] + 1; i++;

because the left operand of += is evaluated once.

If it was not evaluated once it would be the same as:

a[i++] = a[i++] + 1;

which is of course different (and undefined behavior BTW).

Example 2:

*foo() += 1;

assuming foo here returns a pointer to an object of a scalar type and produces side effects (for example it prints a string on the terminal). With the compound assignment operator it will print the string only once and not two times.

Example 3:

REG |= 0x01;

assuming REG here is an IO register (something like #define REG (*(volatile uint8_t *) 0x42)) and that every read to this specific IO register triggers a hardware event. The register will be read only once with the compound assignment operator and not two times.

EDIT: following @R. comment I striked the example 3. I think most compilers do not perform a read in this expression: REG = 31 or two reads with this expression: REG = REG | 0x01.

Community
  • 1
  • 1
ouah
  • 142,963
  • 15
  • 272
  • 331
  • Example 3 is incorrect. Whether you use `|=` or `|` and `=` separately, the register will be read exactly once and written exactly once. This is because the object referenced by the lvalue is not read as part of evaluating the `=` operator. Perhaps what you were thinking of is that `|=` might perform a single-instruction read-modify-write cycle when `|` and `=` separately would not, but I think this assumption is wrong; volatile does not require that and may not (under a strict reading of the requirements on volatile) even allow it. – R.. GitHub STOP HELPING ICE Aug 26 '12 at 21:51
  • @R. I maybe was too quick with the example 3 as it does not correspond to a real world example. Actually most compilers probably do not issue a read with a simple assignment like `REG = 31` (for example `vobj1` in http://gcc.gnu.org/wiki/VolatileAccessComparison ). But I think a compiler is allowed to perform it. I cannot see a difference from the C Standard point of view with this statement: `REG;` the value is also not used but most compilers perform the read. – ouah Aug 26 '12 at 22:16
  • `REG;` should cause a read if `REG` is volatile, because the value of the expression is `REG` even though it's unused. However, reading `REG` is not part of evaluating the expression `REG = 31;` because the `=` operator does not evaluate the *value* of its left-hand side; it only determines the location in which the value on the right-hand side will be stored. – R.. GitHub STOP HELPING ICE Aug 26 '12 at 23:09
  • 1
    C says the left operand of the assignmen operator is evaluated to determine its result *(C99, 6.5.16p3) "An assignment expression has the value of the left operand after the assignment, but is not an lvalue."* In C11 a footnote was added to this sentence that says *"111) The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type."* So I think a read of the register in `(REG = 1)` would even be allowed. – ouah Aug 27 '12 at 07:47
  • Thanks for finding the relevant text and clarifying. – R.. GitHub STOP HELPING ICE Aug 27 '12 at 14:10
2

Usually the += operator is introduced in the following way:

x += y;
x = x+y; // does the same

However, the note tries to tell you that this is in fact not accurate, as the left side of = and += might be any expression. As others have stated this can lead to undefined behaviour, but that's not the core of the issue.

For instance:

char* f() {
  static char value = 'a';
  printf("%c\n",value);
  return &value;
}

void g() {
  *f() = 'b'; // assigns 'b' which was 'a'
  *f() += 2; // changes 'b' to 'd'
  *f() = 'b';
  *f() = *f() + 2; // changes 'b' to 'd'
}

The difference is that f is executed twice in the last line, while it is executed once in the second.

bitmask
  • 32,434
  • 14
  • 99
  • 159
1

Your question is very unclear and poorly worded, but I suspect what your note was in reference to is that the combined arithmetic+assignment operators allow you to do certain things without writing (and thus evaluating) the expression for the lvalue more than once. For instance,

*p++ += *q++;  /* p is incremented once, as desired */
*p++ = *p++ + *q++;  /* undefined behavior */

It especially matters when you'll be using these in macros, for instance:

#define ACCUM(d,s) (d)+=(s) /* good */
#define ACCUM(d,s) (d)=(d)+(s) /* dangerous */
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
0

Don't have anything to compile with handy but here is an interesting tidbit:

var1 += var++ would change the value of var1 to var1 + var

however

var1 += ++var would change the value of var1 to var1 + (var + 1)

Keith Miller
  • 1,337
  • 1
  • 16
  • 32
  • I think this is understood (or not an issue) in the question; the issue is what does it mean for the LHS of the assignment to be evaluated once — why (or when) is that critical? – Jonathan Leffler Aug 26 '12 at 21:01
  • 1
    oh, my mistake I guess I completely missed the point of the question. – Keith Miller Aug 26 '12 at 21:26
0

There are some compound assignment operation in C. for e.g. +=,-=, *=,/=,%=

for e.g. i += 1 It increments the value of i by 1 like i++.

Ajay
  • 6,418
  • 18
  • 79
  • 130
  • I think this is understood in the question; the issue is what does it mean for the LHS of the assignment to be evaluated once — why (or when) is that critical? – Jonathan Leffler Aug 26 '12 at 21:00
  • I'm already familiar with the things You've written, not the case I'm asking here. Anyway thanks for activity ;) – Peter Cerba Aug 26 '12 at 21:00
0

There are number of compound assignment operators. for eg. +=,-=,*=,/=,%=

as a+=b will give a=a+b for more details click on this

Tyler Jandreau
  • 4,245
  • 1
  • 22
  • 47