Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ';静态';值在函数调用后重置_C# - Fatal编程技术网

C# ';静态';值在函数调用后重置

C# ';静态';值在函数调用后重置,c#,C#,我找到了很多关于静态的文章(、、等等),但我仍然不明白为什么这段代码返回-1: class Program { static int value = 0; static int foo() { value = value - 7; return 1; } static void Main(string[] args) { value -= foo(); Console.WriteL

我找到了很多关于静态的文章(、、等等),但我仍然不明白为什么这段代码返回
-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()
之后,但在从
值中减去结果之前显示的内容:

但是一步之后,
-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();
    }
}

我希望
-8
,因为静态字段存储在内存中一次

当我把它改成

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

这到底是怎么回事?

这句话

value -= foo(); // short for value = value - foo();
相当于

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

这就是为什么你会得到
-1

这个问题与静态无关;这是关于减法是如何工作的

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

编译器将解释为四个步骤:

  • value
    的值加载到堆栈上
  • 调用方法
    foo
    ,并将结果放入堆栈
  • 使用堆栈上的这两个值进行减法运算
  • 将结果设置回
    字段
  • 因此,
    value
    字段的原始值已经加载。无论您在方法
    foo
    中更改
    value
    ,减法的结果都不会受到影响

    如果将顺序更改为
    value=-foo()+value
    ,则调用
    foo
    后将加载
    value
    字段的值。结果是
    -8
    ;这就是你期望得到的

    感谢埃利亚胡的评论

    value -= foo(); // value = value - foo();
    
    foo()
    将返回
    1

    value
    最初是
    0
    ,因此:
    0=0-1

    现在,
    值具有
    -1


    因此,问题在于返回
    1

    只需查看生成的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:
      -在堆栈上推送静态字段的值s:[值(0)]
    • IL\u 0006:
      -将
      7
      推到堆栈上s:[7,值(0)]
    • IL\u 0007:
      -从值1(
      0
      )中减去值2(
      7
      ),返回一个新值(-7)
    • IL_0008:
      -将静态字段的值替换为val(值=-7)
    • IL\u 000d:
      -将
      1
      推到堆栈上s:[1,7,值(-7)]
    • IL\u 000e:
      -将堆栈中的值弹出到局部变量0中。(lv=1)
    • IL_0011:
      -将局部变量0加载到堆栈中s:[lv(1),7,值(-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\u 0001:
      -将
      推送到堆栈上(即
      0
    • IL\u 0006:
      -调用
      foo
      (将返回
      1
    • IL\u 000b:
      -从
      value1(0)
      中减去值:
      value2(1)
      value(0)-value(1)=-1
    因此结果是
    -1

    您可以使用菜单调试→ 窗户→ 拆解并检查后台发生的情况:

    我评论了最有趣的部分

        //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 places (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 moves 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, and then print it out to the screen.
        015E04CC  call        54CE8CBC
    
    因此,当编写
    value-=foo()
    时,它确实会生成如下代码:

    value = 0; // In the beginning STEP_A
    
    //... main
    var temp = value; //STEP_B
    temp -= foo(); // STEP_C
    value = temp; // STEP_D
    

    我认为这与它如何在汇编级别减去
    值有关,这会导致程序中出现一些不一致性。我不知道这是否与静电有关。但根据我的直觉,这就是发生的情况:

    让我们关注
    value-=foo()

  • 保存旧的
    (推送到堆栈)
  • foo()
    函数返回
    1
  • 现在,由于
    foo()
    操作,
    值为
    -7
  • 问题是:用
    1
    减去旧的
    (即先前保存的值,即
    0
    ),然后将结果分配给当前的

  • @pappbence96,这正是他所期望的,但没有得到。仅供参考,这与静态无关。已对此进行调试,当方法结束时,值=-7,但下一步它神奇地在“-1”上更改。这是一个无法理解的问题,
    value-=foo()
    value=value(0)的当前值-foo()相同,后者返回1
    ,与
    value=0-1
    相同
    foo()
    只在调用
    foo()
    的计算中引用了
    值之后,才会递减
    值。糟糕的解释让人难以理解,但简而言之就是这样在意义上具有内在的模糊性。有些语言有适当的法律术语来定义这些语句,其他语言(臭名昭著的C族)只是说:“操作数求值的顺序是未定义的。”不管您的语言属于哪一类,这种模棱两可的代码不应该写出来,因为它很难理解。@Bahrom:看起来像你说的那样工作,但为什么呢?@Eliahuaron:因为C#规范这么说。为什么C#spec会这么说?因为(a)具有确定的评估顺序和(b)a-=b表现为a=a-b(而只评估
    a
    一次)都被广泛认为是好主意。你会以不同的方式指定它吗?如果是,如何以及为什么?如果您将
    value=foo()-value
    更改为
    value=-foo()+value
    在你的最后一句话中,你将得到“预期”结果
    -8
    @EliahuAaron…很可能。操作数的求值顺序,因此编译器可以按任意顺序或并行方式求值这两个参数。但是你的评论很有帮助地强调了
    -=
    是一件比最初看起来更复杂的事情