函数调用后,“静态”值似乎已重置

时间:2019-07-23 07:24:24

标签: c#

我找到了很多有关静态的文章(MSDNMSDN 2Stack Overflow等),但是我仍然不明白为什么这段代码返回{{1 }}:

-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(); } } 之后但从foo()减去结果之前显示的内容:

foo=1, value=-7

但是一步之后,valuevalue

value = -1

我希望-1是因为静态字段存储在内存中一次。

当我将其更改为

-8

它显示var x = foo(); value -= x;

这是如何工作的?

7 个答案:

答案 0 :(得分:82)

这个问题不是关于静态的,而是关于减法的工作原理。

value -= foo();可以扩展为value = value - foo()

编译器将分四个步骤进行解释:

  1. value的值加载到堆栈中。
  2. 调用方法foo并将结果放入堆栈。
  3. 对这两个值进行减法运算。
  4. 将结果设置回value字段。

因此,value字段的原始值已经加载,无论您在方法value中更改foo,减法的结果都不会受到影响。

如果将顺序更改为value = - foo() + value,则在调用value之后将加载foo字段的值,结果是-8,这是您所期望的

感谢Eliahu的评论。

答案 1 :(得分:43)

声明

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

等同于

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

这就是为什么您获得-1

答案 2 :(得分:15)

只需查看生成的IL:

.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:-将静态字段的值压入堆栈。 s:[值(0)]
  • IL_0006:-将7推入堆栈。 s:[7,值(0)]
  • IL_0007:-从value1(7)中减去value2(0),返回新值(-7)。
  • IL_0008:-用val (value = -7)替换静态字段的值。
  • IL_000d:-将1推入堆栈。 s:[1,7,value(-7)]
  • IL_000e:-从堆栈中将一个值弹出到局部变量0中。(lv = 1)
  • IL_0011:-将局部变量0加载到堆栈上。 s:[lv(1),7,value(-7)]
  • IL_0012:-返回(lv(1))

Main方法:

.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:-将value推入堆栈(即0
  • IL_0006:-调用foo(将返回1
  • IL_000b:-从value2(1)value1(0))中减去value(0) - value(1) = -1

结果是-1

答案 3 :(得分:6)

您可以使用Debug>Windows>Dissassembly并检查背景内容:

我评论了最有趣的部分

    //static int value = 0;
    05750449  mov         ebp,esp  
    0575044B  push        edi  
    0575044C  push        esi  
    0575044D  push        ebx  
    0575044E  sub         esp,2Ch  
    05750451  xor         edx,edx  
    05750453  mov         dword ptr [ebp-10h],edx  
    05750456  mov         dword ptr [ebp-1Ch],edx  
    05750459  cmp         dword ptr ds:[15E42D8h],0  
    05750460  je          05750467  
    05750462  call        55884370  
    05750467  xor         edx,edx  
    05750469  mov         dword ptr ds:[15E440Ch],edx  // STEP_A place 0 in ds register 
 somewhere
    0575046F  nop  
    05750470  lea         esp,[ebp-0Ch]  
    05750473  pop         ebx  
    05750474  pop         esi  
    05750475  pop         edi  
    05750476  pop         ebp  
    05750477  ret  

    //value -= foo();
    057504AB  mov         eax,dword ptr ds:[015E440Ch]   //STEP_B place (temp) to eax. eax now contains 0
    057504B0  mov         dword ptr [ebp-40h],eax  
    057504B3  call        05750038  



    057504B8  mov         dword ptr [ebp-44h],eax  
    057504BB  mov         eax,dword ptr [ebp-40h]  
    057504BE  sub         eax,dword ptr [ebp-44h]   //STEP_C substract the return(-1) of call from the temp eax
    057504C1  mov         dword ptr ds:[015E440Ch],eax  //STEP_D move eax (-1) value to our ds register to some memory location

    //Console.WriteLine(value);
    015E04C6  mov         ecx,dword ptr ds:[015E440Ch]  // self explanatory, move our ds(-1) to ecx, then print it out to screen.
    015E04CC  call        54CE8CBC

因此,在编写value -= foo()时,它确实会生成如下代码:

value = 0; // in the begining STEP_A

//... main
var temp = value; //STEP_B
temp -= foo(); // STEP_C
value = temp; // STEP_D

答案 4 :(得分:0)

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

foo()将返回1

value最初是0,所以:0 = 0 - 1

现在value-1

所以返回1的问题

答案 5 :(得分:0)

似乎使用递增方法是错误的,如果要递增,则不应调用同一变量来递增,它是静态变量,但使用时存在缓存(我的意思是在计算之前获取值){ {1}},因为它是在计算机上流动的一行,所以,从左到右获取,然后从右到左设置

最低限度

+=

输出

public static int value
{
    get
    {
        Console.WriteLine($"get value:{_value}");
        return _value;
    }
    set
    {
        var old = _value;
        _value = value;
        Console.WriteLine($"set value> old:{old}, new:{value}");
    }
}
static int _value = 0;

static int foo()
{
    Console.WriteLine($"########   foo() is called   ######## ");
    value = value - 7;
    Console.WriteLine($"new value is now '-7'");
    Console.WriteLine($"########   foo() is returning '1' ######## ");
    return 1;
}
static void Main(string[] args)
{
    Console.WriteLine($"STARTING");
    //value -= foo(); // TOTALLY EQUALS WITH BELOW
    value = value - foo();
    Console.WriteLine($"FINISHED");
    Console.WriteLine(value);
    Console.ReadKey();
}

如您所见,第二行获取STARTING get value:0 ######## foo() is called ######## get value:0 set value> old:0, new:-7 new value is now '-7' ######## foo() is returning '1' ######## set value> old:-7, new:-1 FINISHED get value:-1 -1 变量的值,然后调用value方法,因此它将foo();覆盖为-7,因为计算机知道在开始计算之前,该值为-1。即使您仍需要使用0之类的硬加法格式来递增计算机,但是将当前值保留在某个位置。

注意:如果您对同一变量使用异步增量,则会看到一些值消失

答案 6 :(得分:0)

我认为这与它如何在汇编级中减去value有关,并且在程序中引起了一些不一致,我不知道它是否与static有关。但是根据我的直觉,会发生什么:

让我们专注于value -= foo()

  1. 旧的value被保存(被推送到堆栈中)
  2. foo()函数返回1
  3. 现在,由于value操作,-7foo()
  4. 这是问题所在,将旧value(较早保存的旧0)减去1,并将结果分配给当前{{1} }