我找到了很多有关静态的文章(MSDN,MSDN 2,Stack Overflow等等),但是我仍然不明白为什么此代码返回-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();
}
}
Run Code Online (Sandbox Code Playgroud)
这是调试器在foo()运行后但从中减去结果之前显示的内容value:
但是,下一步value是-1:
我希望-8因为静态字段存储在内存中一次。
当我将其更改为
var x = foo();
value -= x;
Run Code Online (Sandbox Code Playgroud)
表明 -8
究竟如何运作?
shi*_*ngo 132
这个问题与静态无关。这是关于减法的工作原理。
value -= foo(); 可以扩展到 value = value - foo()
编译器将解释为四个步骤:
value到堆栈上。foo并将结果放入堆栈。value字段。因此,value字段的原始值已经加载。无论您value对方法进行什么更改,foo减法的结果都不会受到影响。
如果将顺序更改为value = - foo() + value,则将在调用value后加载field 的值foo。结果是-8;这就是您期望得到的。
感谢Eliahu的评论。
Bah*_*rom 63
该声明
value -= foo(); // short for value = value - foo();
Run Code Online (Sandbox Code Playgroud)
相当于
var temp = value; // 0
var fooResult = foo(); // 1
value = temp - fooResult; // -1
Run Code Online (Sandbox Code Playgroud)
这就是为什么你得到 -1
SᴇM*_*SᴇM 34
只需查看生成的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
Run Code Online (Sandbox Code Playgroud)
IL_0001:-将静态字段的值压入堆栈。s:[值(0)]IL_0006:-推7入堆栈。s:[7,值(0)]IL_0007:- 7从value1(0)中减去value2(),返回新值(-7)。IL_0008:-用val (值= -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
Run Code Online (Sandbox Code Playgroud)
IL_0001:-推入value堆栈(即0)IL_0006:-通话foo(将返回1)IL_000b:- value2(1)从value1(0)(value(0) - value(1) = -1)中减去值:结果是-1。
kov*_*oli 18
您可以使用菜单调试 → Windows → 反汇编并检查后台发生了什么:
我评论了最有趣的部分。
//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
Run Code Online (Sandbox Code Playgroud)
因此,在编写时value -= foo(),它确实会生成如下代码:
value = 0; // In the beginning STEP_A
//... main
var temp = value; //STEP_B
temp -= foo(); // STEP_C
value = temp; // STEP_D
Run Code Online (Sandbox Code Playgroud)
小智 7
我认为这与它value在汇编级别上的减法有关,并且导致程序中的某些不一致。我不知道它是否与静态有关。但是根据我的直觉,会发生以下情况:
让我们专注于 value -= foo()
value保存(推入堆栈)foo()函数返回1value是-7由于foo()操作value(这是较早保存的OLD 0)减去,1并将结果分配给current value。小智 5
value -= foo(); // value = value - foo();
Run Code Online (Sandbox Code Playgroud)
foo()会回来的1。
value最初是0这样的:0 = 0 - 1。
现在value有-1。
所以问题在于回报1。