c# - फ़ंक्शन कॉल[डुप्लिकेट] के बाद 'स्थिर' मान रीसेट हो जाता है
(4)
आप मेनू डिबग → विंडोज → डिस्सैड का उपयोग कर सकते हैं और जांच सकते हैं कि पृष्ठभूमि में क्या होता है:
मैंने सबसे दिलचस्प हिस्सों पर टिप्पणी की।
//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
इस सवाल का पहले से ही यहाँ एक जवाब है:
मुझे स्टैटिक्स (
MSDN
,
MSDN 2
,
स्टैक ओवरफ़्लो
और बहुत अधिक) के बारे में बहुत सारे लेख मिले, लेकिन मैं अभी भी नहीं समझ पा रहा हूं कि यह कोड
-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;
यह दिखाता है
-8
यह ठीक कैसे काम करता है?
जनरेट किए गए 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:
- स्टैक पर स्थिर फ़ील्ड का मान पुश करें। रों: [मान (0)] -
IL_0006:
- स्टैक पर7
पुश करें। s: [7, मान (0)] -
IL_0007:
- मान 1 (0
) से मूल्य7
(7
) घटाकर, एक नया मान (-7) लौटाता है। -
IL_0008:
- स्थैतिक क्षेत्र के मान को वेल (मान = -7) से बदल देता है । -
IL_000d:
- स्टैक पर1
पुश करें। s: [१, 7, मान (-7)] -
IL_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_0001:
- स्टैक परvalue
धक्का (जो0
) -
IL_0006:
- कॉलfoo
(जो1
लौटेगी) -
IL_000b:
- मान घटाएँ:value2(1)
value1(0)
(value(0) - value(1) = -1
) से।
तो परिणाम
-1
।
मुझे लगता है कि इसका विधानसभा स्तर पर
value
घटाने के साथ कुछ करना है, और इससे कार्यक्रम में कुछ असंगति पैदा होती है।
मुझे नहीं पता कि इसका स्टैटिक के साथ कुछ लेना-देना है या नहीं।
लेकिन मेरे अंतर्ज्ञान से यही होता है:
आइए
value -= foo()
पर ध्यान दें
value -= foo()
-
पुराना
value
सहेज लिया गया (स्टैक पर धकेला गया) -
foo()
फ़ंक्शन1
देता है -
अब,
foo()
ऑपरेशन के कारणvalue
-7
-
यहाँ समस्या है: OLD
value
(जो पहले सहेजा गया है, जो कि0
)1
साथ घटाया गया है और परिणाम वर्तमानvalue
को सौंपा गया है।
यह समस्या स्थैतिक के बारे में नहीं है; यह घटाव कैसे काम करता है, इसके बारे में है।
value -= foo();
विस्तार किया जा सकता है
value = value - foo()
संकलक इसे चार चरणों में समझाएगा:
-
स्टैक पर मूल्य का
value
लोड करें। -
विधि
foo
कॉल करें और परिणाम को स्टैक पर रखें। - स्टैक पर इन दो मूल्यों के साथ घटाव करें।
-
परिणाम को वापस
value
फ़ील्ड पर सेट करें।
तो
value
फ़ील्ड का मूल मान पहले से लोड है।
जो भी आप विधि
foo
में
value
बदलते हैं, घटाव का परिणाम प्रभावित नहीं होगा।
यदि आप ऑर्डर को
value = - foo() + value
बदलते हैं, तो
foo
कहलाने के बाद
value
फील्ड की
value
लोड हो जाएगी।
परिणाम है
-8
;
आपसे यही अपेक्षित है।
एलियाहू की टिप्पणी के लिए धन्यवाद।