我找到了很多有关静态的文章(MSDN,MSDN 2,Stack 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()
减去结果之前显示的内容:
但是一步之后,value
是value
:
我希望-1
是因为静态字段存储在内存中一次。
当我将其更改为
-8
它显示var x = foo();
value -= x;
这是如何工作的?
答案 0 :(得分:82)
这个问题不是关于静态的,而是关于减法的工作原理。
value -= foo();
可以扩展为value = value - foo()
编译器将分四个步骤进行解释:
value
的值加载到堆栈中。foo
并将结果放入堆栈。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()
value
被保存(被推送到堆栈中)foo()
函数返回1
value
操作,-7
是foo()
value
(较早保存的旧0
)减去1
,并将结果分配给当前{{1} }