c# फ़ंक्शन कॉल[डुप्लिकेट] के बाद 'स्थिर' मान रीसेट हो जाता है




(5)

इस सवाल का पहले से ही यहाँ एक जवाब है:

मुझे स्टैटिक्स ( 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

यह ठीक कैसे काम करता है?


यह समस्या स्थैतिक के बारे में नहीं है; यह घटाव कैसे काम करता है, इसके बारे में है।

value -= foo(); विस्तार किया जा सकता है value = value - foo()

संकलक इसे चार चरणों में समझाएगा:

  1. स्टैक पर मूल्य का value लोड करें।
  2. विधि foo कॉल करें और परिणाम को स्टैक पर रखें।
  3. स्टैक पर इन दो मूल्यों के साथ घटाव करें।
  4. परिणाम को वापस value फ़ील्ड पर सेट करें।

तो value फ़ील्ड का मूल मान पहले से लोड है। जो भी आप विधि foo में value बदलते हैं, घटाव का परिणाम प्रभावित नहीं होगा।

यदि आप ऑर्डर को value = - foo() + value बदलते हैं, तो foo कहलाने के बाद value फील्ड की value लोड हो जाएगी। परिणाम है -8 ; आपसे यही अपेक्षित है।

एलियाहू की टिप्पणी के लिए धन्यवाद।


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

foo() 1 लौटेगा।

value शुरू में 0 , इसलिए: 0 = 0 - 1

अब value है -1

तो मुद्दा वापसी 1 साथ है।


बयान

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

के बराबर है

var temp = value; // 0
var fooResult = foo(); // 1
value = temp - fooResult; // -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: - स्टैक पर स्थिर फ़ील्ड का मान पुश करें। रों: [मान (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


आप मेनू डिबग विंडोज डिस्सैड का उपयोग कर सकते हैं और जांच सकते हैं कि पृष्ठभूमि में क्या होता है:

मैंने सबसे दिलचस्प हिस्सों पर टिप्पणी की।

    //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



c#  

c#