Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'static' value appears to reset after function call [duplicate]

Tags:

c#

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:

foo=1, value=-7

But one step later, value is -1:

value = -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?

like image 567
EmerG Avatar asked Jul 23 '19 07:07

EmerG


3 Answers

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.

like image 127
shingo Avatar answered Nov 20 '22 04:11

shingo


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

like image 41
DotNet Developer Avatar answered Nov 20 '22 03:11

DotNet Developer


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.

like image 33
SᴇM Avatar answered Nov 20 '22 02:11

SᴇM