'static' value appears to reset after function call

Just look at the generated CIL:

.method private hidebysig static int32  foo() cil managed
{
  // Code size       19 (0x13)
  .maxstack  2
  .locals init ([0] int32 V_0)
  IL_0000:  nop
  IL_0001:  ldsfld     int32 Program::'value'
  IL_0006:  ldc.i4.7
  IL_0007:  sub
  IL_0008:  stsfld     int32 Program::'value'
  IL_000d:  ldc.i4.1
  IL_000e:  stloc.0
  IL_000f:  br.s       IL_0011
  IL_0011:  ldloc.0
  IL_0012:  ret
} // end of method Program::foo
  • IL_0001: - Push the value of the static field on the stack. s:[value(0)]
  • IL_0006: - Push 7 onto the stack. s:[7, value(0)]
  • IL_0007: - Subtracts value2 (7) from value1 (0), returning a new value (-7).
  • IL_0008: - Replaces the value of the static field with val (value = -7).
  • IL_000d: - Push 1 onto the stack. s:[1, 7, value(-7)]
  • IL_000e: - Pop a value from stack into local variable 0. (lv = 1)
  • IL_0011: - Load local variable 0 onto stack. s:[lv(1), 7, value(-7)]
  • IL_0012: - Return (lv(1))

And the Main method:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       29 (0x1d)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldsfld     int32 Program::'value'
  IL_0006:  call       int32 Program::foo()
  IL_000b:  sub
  IL_000c:  stsfld     int32 Program::'value'
  IL_0011:  ldsfld     int32 Program::'value'
  IL_0016:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_001b:  nop
  IL_001c:  ret
} // end of method Program::Main
  • IL_0001: - pushes value onto stack (which is 0)
  • IL_0006: - calls foo (which will return 1)
  • IL_000b: - subtract values: value2(1) from value1(0) (value(0) - value(1) = -1).

So the result is -1.


This problem is not about static; it's about how the subtraction works.

value -= foo(); can be expanded to value = value - foo()

The compiler will explain it into four steps:

  1. Load the value of value onto the stack.
  2. Call the method foo and put the result onto the stack.
  3. Do subtraction with these two values on the stack.
  4. Set the result back to value field.

So the original value of value field is already loaded. Whatever you change value in the method foo, the result of the subtraction won't be affected.

If you change the order to value = - foo() + value, then the value of value field will be loaded after foo is called. The result is -8; that's what you are expected to get.

Thanks for Eliahu's comment.


The statement

value -= foo(); // short for value = value - foo();

is equivalent to

var temp = value; // 0
var fooResult = foo(); // 1
value = temp - fooResult; // -1

That's why you are getting -1

Tags:

C#