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