Is there any explanation for inline operators k += c += k += c;

  • A+
Category:Languages

Can anyone explain the result from this operation:

k += c += k += c; 

I was trying to understand the output result from the following code:

int k = 10; int c = 30; k += c += k += c; //k=80 instead of 110 //c=70 

and currently I am struggling with understanding why the result for "k" is 80. Why is assigning k=40 not working (actually VS tells me that that value is not being used elsewhere)?

Can anyone help me to understand why k is 80 and not 110?

If I split the operation to:

k+=c; c+=k; k+=c; 

the result is k=110.

I was trying to look through IL, but I am not so profound in interpreting generated IL and can not get a few details:

 // [11 13 - 11 24] IL_0001: ldc.i4.s     10 IL_0003: stloc.0      // k  // [12 13 - 12 24] IL_0004: ldc.i4.s     30 IL_0006: stloc.1      // c  // [13 13 - 13 30] IL_0007: ldloc.0      // k expect to be 10 IL_0008: ldloc.1      // c IL_0009: ldloc.0      // k why do we need the second load? IL_000a: ldloc.1      // c IL_000b: add          //expect to be 40 IL_000c: dup          //what for? IL_000d: stloc.0      // k - expected to be 40 IL_000e: add           IL_000f: dup          //I presume the "magic" happens here IL_0010: stloc.1      // c = 70 IL_0011: add           IL_0012: stloc.0      // k = 80?????? 

 


An operation like a op= b; is equivalent to a = a op b;. An assignment can be used as statement or as expression, while as expression it yields the assigned value. Your statement

k += c += k += c; 

can be translated to the equivalent one (since the assignment operator is right-associative)

k += (c += (k += c)); 

or expanded

k =  k + (c = c + (k = k + c));                   40 ← 10  30          70 ← 30  40 80 ← 10  70 

Where during the whole evaluation the old values of the involved variables are used. This is especially true for the value of k (see my review of the IL below and the link Wai Ha Lee provided). Therefore, you are not getting 70 + 40 (new value of k) = 110, but 70 + 10 (old value of k) = 80.


Now let's look at the IL. IL assumes a stack based virtual machine, i.e. it does not use registers.

IL_0007: ldloc.0      // k (is 10) IL_0008: ldloc.1      // c (is 30) IL_0009: ldloc.0      // k (is 10) IL_000a: ldloc.1      // c (is 30) 

The stack now looks like this (from left to right; top of stack is right)

10 30 10 30

IL_000b: add          // pops the 2 top (right) positions, adds them and pushes the sum 

10 30 40

IL_000c: dup 

10 30 40 40

IL_000d: stloc.0      // k <-- 40 

10 30 40

IL_000e: add 

10 70

IL_000f: dup 

10 70 70

IL_0010: stloc.1      // c <-- 70 

10 70

IL_0011: add 

80

IL_0012: stloc.0      // k <-- 80 

Note that IL_000c: dup, IL_000d: stloc.0, i.e. the first assignment to k , could be optimized away. Probably this is done by the jitter when converting IL to machine code.

Note also that all the values required by the calculation are either pushed to the stack before any assignment is made or are calculated from these values. Assigned values (by stloc) are never re-used during this evaluation. stloc pops the top of the stack.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: