I found a lot of articles about statics (MSDN, MSDN 2, Stack Overflow, and lot lot more), but I still can't understand why this code returns -1:
class Program
{
static int value = 0;
static int foo()
{
value = value - 7;
return 1;
}
static void Main(string[] args)
{
value -= foo();
Console.WriteLine(value);
Console.ReadKey();
}
}
Here's what the debugger shows after foo() has run, but before the result is subtracted from value:

But one step later, value is -1:

I would expect -8 because of the static field which is stored in memory once.
When I changed it to
var x = foo();
value -= x;
it shows -8
How does this work exactly?
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:
value onto the stack.foo and put the result onto the stack.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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With