I = 0 के लिए, क्यों (i + = i ++) 0 के बराबर है?


253

निम्न कोड लें (कंसोल एप्लिकेशन के रूप में प्रयोग करने योग्य):

static void Main(string[] args)
{
    int i = 0;
    i += i++;
    Console.WriteLine(i);
    Console.ReadLine();
}

का परिणाम iहै 0. मुझे उम्मीद है कि 2 (जैसा कि मेरे कुछ सहयोगियों ने किया था)। संभवतः संकलक कुछ प्रकार की संरचना बनाता है जिसके परिणामस्वरूप iशून्य होता है।

मेरे द्वारा अपेक्षित 2 कारण है, मेरे विचार की पंक्ति में, दाहिने हाथ के बयान का मूल्यांकन पहले किया जाएगा, 1 के साथ i वृद्धी। यह मुझे i से जोड़ा गया है। चूंकि मैं पहले से ही 1 है, इसलिए यह 1 से 1. जोड़ रहा है। इसलिए 1 + 1 = 2. जाहिर है कि यह नहीं हो रहा है।

क्या आप समझा सकते हैं कि संकलक क्या करता है या रनटाइम पर क्या होता है? परिणाम शून्य क्यों है?

कुछ-प्रकार की अस्वीकरण: मैं पूरी तरह से अवगत हूं आप इस कोड का उपयोग नहीं करेंगे (और शायद नहीं करना चाहिए)। मुझे पता है मैं कभी नहीं करूंगा। फिर भी, मुझे पता है कि यह जानना दिलचस्प है कि यह इस तरह से क्यों काम करता है और वास्तव में क्या हो रहा है।


57
क्या अपेक्षित परिणाम 1 नहीं होना चाहिए? i (0) + = i ++ (1) इसलिए 0 + = 1 = 1
रूपांतरण

11
यह उम्मीद के
मुताबिक

177
इस प्रश्न के कितने रूपांतर पूछे जाने वाले हैं?
मावलवकर

20
Preincrementation एसीन करने से पहले मूल्य वृद्धि करेगा i + = ++ मैं आपको 1 देगा
पियरलुक एसएस

21
क्यों हर कोई पूर्व बनाम पोस्टक्रीमेंट पर ध्यान केंद्रित कर रहा है? "अजीब" बात यह है कि मूल्य के iके बाएं हाथ की ओर +=दाएँ हाथ की ओर से पहले "कैश की गई" है मूल्यांकन किया जाता है। यह काउंटर-सहज ज्ञान युक्त है, जैसा कि उदाहरण के लिए, iएक ऑब्जेक्ट होने पर कॉपी ऑपरेशन की आवश्यकता होती है । (कृपया मुझे गलत न समझें: मैं बिल्कुल 0सही और मानक-अनुरूप जवाब देने के लिए सहमत हूं ।)
जॉन्बी

जवाबों:


425

यह:

int i = 0;
i += i++

जैसा कि आप कर रहे हैं देखा जा सकता है (निम्नलिखित एक स्थूल निरीक्षण है):

int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result

वास्तव में जो कुछ होता है, वह इससे कहीं अधिक शामिल है - MSDN, 7.5.9 पोस्टफिक्स इंक्रीमेंट और डिक्रीमेंट ऑपरेटरों पर एक नज़र डालें :

प्रपत्र x ++ या x-- के पोस्टफ़िक्स इन्क्रीमेंट या डिक्रीमेंट ऑपरेशन की रन-टाइम प्रोसेसिंग में निम्न चरण होते हैं:

  • यदि x को एक चर के रूप में वर्गीकृत किया गया है:

    • चर का उत्पादन करने के लिए x का मूल्यांकन किया जाता है।
    • X का मान सहेजा गया है।
    • चयनित ऑपरेटर को उसके तर्क के रूप में x के सहेजे गए मान के साथ लागू किया जाता है।
    • ऑपरेटर द्वारा लौटाए गए मान को x के मूल्यांकन द्वारा दिए गए स्थान पर संग्रहीत किया जाता है।
    • एक्स का सहेजा गया मान ऑपरेशन का परिणाम बन जाता है।

ध्यान दें कि पूर्ववर्ती क्रम के कारण , पोस्टफ़िक्स पहले++ होता है , लेकिन परिणाम अप्रयुक्त होने के रूप में समाप्त होता है (जैसा कि पिछले मूल्य का उपयोग किया जाता है)। +=i


की एक अधिक गहन अपघटन i += i++भागों यह से बना है को पता चला है कि दोनों एक आवश्यकता है +=और ++परमाणु नहीं हैं (यह है कि, दोनों में से कोई एक भी ऑपरेशन है), भले ही वे देखने के लिए वे कर रहे हैं की तरह। जिस तरह से इन्हें लागू किया जाता है, उसमें अस्थायी चर शामिल होते हैं, iऑपरेशन से पहले की प्रतियां - प्रत्येक ऑपरेशन के लिए एक। (मैं नाम का उपयोग करेगा iAddऔर iAssignअस्थायी के लिए इस्तेमाल किया चर के लिए ++और +=क्रमशः)।

तो, क्या हो रहा है के लिए एक निकट सन्निकटन होगा:

int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=

i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;

3
@ ओक्ड स्टेटमेंट का मूल्यांकन ++पूर्ण होने से पहले किया जाता है । इसलिए +=मूल्य को ओवरराइट करता है। यह क्या हो गया?
अनिरुद्ध रामनाथन

6
@ वास्तव में इसकी int i = 0; i = i + 1; (postfix) i = 0; (assignment):। यदि आप उस कथन में अन्यत्र उपयोग करते हैं, तो यह उस समय 1 का मूल्यांकन करेगा।
drch

@ कथुलु - अनिवार्य रूप से। जवाब से DTB विवरण में चला जाता है।
ऊद

6
मैं इसे नहीं खरीदता। @Yoriy द्वारा उत्तर अधिक सटीक है। एक के लिए, आपके उत्तर में, आप कहते हैं कि अंतिम पंक्ति होगी i+1जबकि यह होनी चाहिए i=i+1। नहीं है कि क्या i++है?
पुनर्विचार

3
उत्तर का पहला भाग निरर्थक है। आपका अंतिम कोड नमूना IMHO कर सकता है। हालांकि +1।
corazza

194

चल रहे कोड की गड़बड़ी:

int i = 0;
  xor         edx, edx
  mov         dword ptr i, edx         // set i = 0
i += i++;
  mov         eax, dword ptr i         // set eax = i (=0)
  mov         dword ptr tempVar1, eax  // set tempVar1 = eax (=0)
  mov         eax, dword ptr i         // set eax = 0 ( again... why??? =\ )
  mov         dword ptr tempVar2, eax  // set tempVar2 = eax (=0)
  inc         dword ptr i              // set i = i+1 (=1)
  mov         eax, dword ptr tempVar1  // set eax = tempVar1 (=0)
  add         eax, dword ptr tempVar2  // set eax = eax+tempVar2 (=0)
  mov         dword ptr i, eax         // set i = eax (=0)

समतुल्य कूट

यह निम्नलिखित कोड के समान कोड का संकलन करता है:

int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;

दूसरे कोड का डिस्सैडफ़ॉर्म (सिर्फ यह साबित करने के लिए कि वे समान हैं)

int i, tempVar1, tempVar2;
i = 0;
    xor         edx, edx
    mov         dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar2, eax
++i;
    inc         dword ptr i
i = tempVar1 + tempVar2;
    mov         eax, dword ptr tempVar1
    add         eax, dword ptr tempVar2
    mov         dword ptr i, eax

ओपनिंग डिस्सैड विंडो

अधिकांश लोगों को पता नहीं है, या यहां तक ​​कि याद नहीं है, कि वे Visual Studio Disassembly विंडो का उपयोग करके अंतिम इन-मेमोरी असेंबली कोड देख सकते हैं । यह मशीन कोड दिखाता है जिसे निष्पादित किया जा रहा है, यह CIL नहीं है।

डीबग करते समय इसका उपयोग करें:

Debug (menu) -> Windows (submenu) -> Disassembly

तो क्या उपसर्ग ++ के साथ हो रहा है?

पोस्टफिक्स ++ बताता है कि हम मूल्यांकन के बाद ऑपरेंड के मूल्य को बढ़ाना चाहेंगे ... जो कि हर कोई जानता है ... जो थोड़ा सा भ्रमित करता है उसका अर्थ "मूल्यांकन के बाद" है

तो "मूल्यांकन के बाद" क्या मतलब है:

  • कोड के समान लाइन पर ऑपरेंड के अन्य उपयोग प्रभावित होने चाहिए:
    • a = i++ + i दूसरा मैं वेतन वृद्धि से प्रभावित होता हूं
    • Func(i++, i) दूसरा मैं प्रभावित है
  • एक ही लाइन पर अन्य usages शॉर्ट-सर्किट ऑपरेटर का सम्मान करते हैं जैसे ||और &&:
    • (false && i++ != i) || i == 0 तीसरा i i ++ से प्रभावित नहीं है क्योंकि इसका मूल्यांकन नहीं किया गया है

तो का अर्थ क्या है i += i++;:?

यह वैसा ही है i = i + i++;

मूल्यांकन का क्रम है:

  1. स्टोर i + i (वह है 0 + 0)
  2. वृद्धि i (मैं 1 हो जाता है)
  3. चरण 1 से i का मान निर्दिष्ट करें (मैं 0 हो जाता है)

ऐसा नहीं है कि वेतन वृद्धि को खारिज किया जा रहा है।

का अर्थ क्या है i = i++ + i;:?

यह पिछले उदाहरण के समान नहीं है। तीसरा iवेतन वृद्धि से प्रभावित होता है।

मूल्यांकन का क्रम है:

  1. स्टोर i (जो 0 है)
  2. वृद्धि i (मैं 1 हो जाता है)
  3. चरण 1 + i का स्टोर मान (जो कि 0 + 1 है)
  4. चरण 3 से i का मान निर्दिष्ट करें (मैं 1 बनता है)

22
+ 1 ++ - सरासर कट्टर विच्छेदन के लिए। चक नॉरिस को गर्व होगा :) मुझे लगता है कि आप यह अनुमान लगाते हैं कि ओपी इंटेल पर है, न कि मोनो पोर्ट हालांकि ...
स्टुअर्टएलसी

19
C # में अभिव्यक्ति के लिए एक अच्छी तरह से परिभाषित मूल्यांकन आदेश है, और ऑब्जेक्ट कोड उस आदेश को लागू करता है। मूल्यांकन आदेश के लिए मशीन कोड आउटपुट कारण या स्पष्टीकरण नहीं है।
कज़

8
मशीन कोड यह समझना आसान बनाता है कि मूल्यांकन के आदेश को IMO कैसे लागू किया जाता है।
केविन

5
@StuartLC मैं देखता हूं कि आपने वहां क्या किया। शर्म की बात है कि हालांकि अपवित्र छोड़ दिया।
स्टेफेन डोनल

2
a++ + aऐसा नहीं है a + a++क्योंकि यह अब शुद्ध गणित नहीं है। बीजगणित में कम्यूटेटिविटी कानून इस संभावना को ध्यान में नहीं रखता है कि चर एक अभिव्यक्ति के माध्यम से मूल्य मध्य मार्ग को बदलते हैं। जब प्रोग्रामिंग कार्यात्मक प्रोग्रामिंग है तो गणित केवल प्रोग्रामिंग के लिए बड़े करीने से मैप करता है। और तब भी नहीं, प्रतिनिधित्ववादी सीमाओं के कारण। उदाहरण के लिए फ्लोटिंग-पॉइंट नंबर कभी-कभी वास्तविक की तरह व्यवहार करते हैं और कभी-कभी नहीं। साइड इफेक्ट्स के बिना भी, कम्यूटिटी और एसोसिएटिविटी कानून जो गणित में वास्तविक संख्याओं पर लागू होते हैं, फ्लोटिंग-पॉइंट संख्याओं पर टूटते हैं।
काज

61
int i = 0;
i += i++;

मूल्यांकन इस प्रकार है:

Stack<int> stack = new Stack<int>();
int i;

// int i = 0;
stack.Push(0);                   // push 0
i = stack.Pop();                 // pop 0 --> i == 0

// i += i++;
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(1);                   // push 1
i = stack.Pop() + stack.Pop();   // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop();   // pop 0 and 0 --> i == 0

अर्थात iदो बार बदला जाता है: एक बार i++अभिव्यक्ति द्वारा और एक बार +=कथन द्वारा ।

लेकिन +=बयान के संचालक हैं

  • (बाएं हाथ की ओर ) iके मूल्यांकन से पहले मूल्य औरi+++=
  • (दाएं हाथ की ओर ) iके मूल्यांकन से पहले मूल्य ।i+++=

आह यह एक शानदार व्याख्या है। मुझे याद दिलाता है कि जब मैंने रिवर्स पॉलिश नोटेशन का उपयोग करके स्टैक आधारित कैलकुलेटर पर काम किया था।
नाथन

36

सबसे पहले, i++रिटर्न 0. फिर iवृद्धि होती है। 1. अंतिम रूप iसे प्रारंभिक मूल्य पर सेट किया जाता है, iजो 0 से अधिक है i++, जो लौटाया गया मान है , जो शून्य भी है। ० + ० = ०।


2
लेकिन यह i += i++;नहीं है i = i++;, इसलिए i++(0) का मान जोड़ा जाता है i, और " लौटाए iगए मान पर सेट नहीं है i++"। अब सवाल है, जब मूल्य जोड़ने i++के लिए लौट आए i, होगा iवृद्धि मूल्य या नहीं-वृद्धि मूल्य हो सकता है? जवाब, मेरे दोस्त, चश्मे में लिखा है।
डैनियल फिशर

सच है, मैं इसे ठीक कर दूँगा। लेकिन वैसे भी i = 0शुरू से ही, i += somethingइसके बराबर i = 0 + somethingहै i = something
जोंग

32

यह अमूर्त सिंटैक्स ट्री के नीचे, दाएं-बाएं मूल्यांकन है। वैचारिक रूप से, अभिव्यक्ति का पेड़ ऊपर से नीचे चला जाता है, लेकिन मूल्यांकन प्रकट होता है क्योंकि पुनरावृत्ति पेड़ के नीचे से ऊपर जाती है।

// source code
i += i++;

// abstract syntax tree

     +=
    /  \
   i    ++ (post)
         \
         i

जड़ नोड पर विचार करके मूल्यांकन शुरू होता है +=। यह अभिव्यक्ति का प्रमुख घटक है। +=उस स्थान को निर्धारित करने के लिए बाएं ऑपरेंड का मूल्यांकन किया जाना चाहिए जहां हम चर को संग्रहीत करते हैं, और पूर्व मान प्राप्त करने के लिए जो शून्य है। अगला, सही पक्ष का मूल्यांकन किया जाना चाहिए।

दाईं ओर एक पोस्ट-इन्क्रीमेंट ++ऑपरेटर है। इसका एक ऑपरेंड है, iजिसका मूल्यांकन मूल्य के स्रोत के रूप में किया जाता है, और ऐसे स्थान के रूप में जहां मूल्य को संग्रहीत किया जाना है। ऑपरेटर उस स्थान में मूल्यांकन करता है i, खोजता है 0और फलस्वरूप उसे स्टोर करता है 1। यह पूर्व मूल्य वापस करने 0के अपने शब्दार्थ के अनुसार , पूर्व मूल्य लौटाता है ।

अब नियंत्रण +=ऑपरेटर पर वापस आ गया है । अब इसके संचालन को पूरा करने के लिए सभी जानकारी है। यह उस स्थान को जानता है जहां परिणाम (भंडारण स्थान i) के साथ-साथ पूर्व मूल्य को संग्रहीत करना है , और इसका मूल्य पूर्व मूल्य में जोड़ा गया है, अर्थात् 0। तो, iशून्य के साथ समाप्त होता है।

जावा की तरह, C # ने मूल्यांकन के क्रम को ठीक करके C भाषा के एक बहुत ही पहलू को साफ कर दिया है। लेफ्ट-टू-राइट, बॉटम-अप: सबसे स्पष्ट क्रम जो कोडरों द्वारा अपेक्षित होने की संभावना है।


+1: मैं आपके साथ सहमत हूं, सिवाय इसके कि हर कोडर उम्मीद करता है कि ... मुझे उम्मीद थी कि यह कुछ इस तरह से होगा: के SetSum(ref i, Inc(ref i))साथ int SetSum(ref int a, int b) { return a += b; }और int Inc(ref int a) { return a++; }... बेशक मैं अब और उम्मीद नहीं करता।
मिगुएल एंजेलो

इसके अलावा, मुझे जो उम्मीद थी वह असंगत है! यह और के Set(ref i, Sum(i, Inc(ref i)))साथ बराबर नहीं होगा । int Set(ref int a, int b) { return a = b; }int Sum(int a, int b) { return a + b; }
मिगुएल एंजेलो

धन्यवाद; आप मेरे जवाब में एक दोष / अपूर्णता की ओर संकेत करते हैं जिसे मुझे ठीक करना है।
काज

इसके साथ मुद्दा SetSumयह है कि यह बाएं ऑपरेंड का मूल्यांकन नहीं करता है i, लेकिन केवल इसका पता लेता है, इसलिए यह ऑपरेंड के सही मूल्यांकन के लिए पूरी तरह से बाएं के बराबर नहीं है। आपको कुछ चाहिए SetSum(ref i, i, PostInc(ref i))। का दूसरा तर्क SetSumजोड़ा जाने वाला मान है, जहां हम सिर्फ iपूर्व मूल्य निर्दिष्ट करने के लिए उपयोग करते हैं iSetSumबस है int SetSum(ref int dest, int a, int b) { return dest = a + b; }
काज

भ्रम + = ऑपरेटर के साथ (मेरे लिए कम से कम) होता है, क्योंकि असाइनमेंट ऑपरेटर के पास दाएं-से-बाएं मूल्यांकन होता है (जैसे a = b = c = d) ... तो कोई सोच सकता है कि + = समान नियम का पालन करता है, एक परमाणु संचालन के रूप में (जैसा कि मैंने अपनी सेटसुम विधि के साथ किया था) ... लेकिन वास्तव में क्या होता है कि C # में अनुवाद a += bकरता है a = a + b... यह दिखाते हुए कि + = ऑपरेटर परमाणु नहीं है ... यह केवल वाक्यात्मक चीनी है।
मिगुएल एंजेलो

30

क्योंकि i++पहले मूल्य लौटाता है, फिर इसे बढ़ाता है। लेकिन मैं 1 पर सेट होने के बाद, आप इसे 0 पर सेट करते हैं।


17

वेतन वृद्धि के बाद की पद्धति कुछ इस प्रकार है

int ++(ref int i)
{
    int c = i;
    i = i + 1;
    return c;
}

इसलिए मूल रूप से जब आप कॉल करते हैं i++, iतो वृद्धि होती है, लेकिन मूल मान आपके मामले में वापस आ जाता है, यह 0 लौटाया जा रहा है।



12

i ++ का अर्थ है: iENEN का मान बढ़ाएं।

i + = i ++ का अर्थ है: i का वर्तमान मूल्य लो। I ++ का परिणाम जोड़ें।

अब, आइए i = 0 को एक प्रारंभिक स्थिति के रूप में जोड़ें। i + = i ++ का अब इस तरह मूल्यांकन किया जाता है:

  1. मैं का वर्तमान मूल्य क्या है? यह 0. स्टोर है, इसलिए हम i ++ के परिणाम को इसमें जोड़ सकते हैं।
  2. I ++ का मूल्यांकन करें (0 का मूल्यांकन करता है क्योंकि यह i का वर्तमान मूल्य है)
  3. संग्रहीत मूल्य को लोड करें और चरण 2 के परिणाम को इसमें जोड़ें। (0 से 0 जोड़ें)

नोट: चरण 2 के अंत में, i का मूल्य वास्तव में 1. है, हालांकि, चरण 3 में, आप इसे बढ़ाने से पहले i का मान लोड करके इसे छोड़ देते हैं।

जैसा कि i ++ के विपरीत है, ++ मैं वेतन वृद्धि मान लौटाता हूं।

इसलिए, मैं + = ++ मैं आपको 1 देगा।


यह मदद पूर्ण है
sonsha

11

पोस्ट फिक्स वेतन वृद्धि ऑपरेटर, ++चर को अभिव्यक्ति में एक मूल्य देता है और फिर आपके द्वारा दिया गयाi वेतन वृद्धि शून्य (0) मान को फिर से करता है जो वेतन वृद्धि (1) को अधिलेखित करता है , इसलिए आपको शून्य मिल रहा है। आप ++ ऑपरेटर (MSDN) में वेतन वृद्धि ऑपरेटर के बारे में अधिक पढ़ सकते हैं ।


8

i += i++;शून्य के बराबर होगा, क्योंकि यह ++बाद में करता है ।

i += ++i; पहले कर लेंगे


4
यदि यह ++बाद में होता है, तो मुझे उम्मीद है कि परिणाम होगा 1
comecme

8

++ पोस्टफिक्स iइसे बढ़ाने से पहले मूल्यांकन करता है, और +=केवल iएक बार मूल्यांकन करता है ।

इसलिए, 0 + 0 = 0, जैसा iकि मूल्यांकन किया गया है और इसका उपयोग होने से पहले उपयोग किया जाता है, क्योंकि पोस्टफिक्स फॉर्मेट का ++उपयोग किया जाता है। iपहले वृद्धि प्राप्त करने के लिए , उपसर्ग फॉर्म ( ++i) का उपयोग करें ।

(इसके अलावा, सिर्फ एक नोट: आपको केवल 1 प्राप्त करना चाहिए, जैसा कि 0 + (0 + 1) = 1)

संदर्भ: http://msdn.microsoft.com/en-us/library/sa7629ew.aspx (+ =)
http://msdn.microsoft.com/en-us/library/36x43w8w.aspx (++)


8

सी # क्या कर रहा है, और भ्रम की "क्यों"

मुझे भी मूल्य 1 होने की उम्मीद थी ... लेकिन उस मामले पर कुछ अन्वेषण ने कुछ बिंदुओं को स्पष्ट किया।

निम्नलिखित विधियों को कोइडर करें:

    static int SetSum(ref int a, int b) { return a += b; }

    static int Inc(ref int a) { return a++; }

मुझे उम्मीद थी कि i += i++ऐसा ही होगा SetSum(ref i, Inc(ref i))। इस कथन के बाद i का मान 1 है :

int i = 0;
SetSum(ref i, Inc(ref i));
Console.WriteLine(i); // i is 1

लेकिन फिर मैं एक और निष्कर्ष पर आया ... i += i++वास्तव में ऐसा ही है i = i + i++... इसलिए मैंने इन कार्यों का उपयोग करके एक और समान उदाहरण बनाया है:

    static int Sum(int a, int b) { return a + b; }

    static int Set(ref int a, int b) { return a = b; }

इसे कॉल करने Set(ref i, Sum(i, Inc(ref i)))के बाद i का मान 0 है :

int i = 0;
Set(ref i, Sum(i, Inc(ref i)));
Console.WriteLine(i); // i is 0

यह न केवल यह बताता है कि C # क्या कर रहा है ... बल्कि यह भी कि बहुत सारे लोग इसे लेकर भ्रमित हो गए ... मेरे सहित।


2
कृपया इसे अपने मूल उत्तर में जोड़ें, इससे अलग उत्तर के रूप में होने का कोई लाभ नहीं है।
कास्परऑन

2
मैंने ऐसा नहीं किया दूसरे जवाब को टालने के लिए, क्योंकि यह विघटित कोड के बारे में है ... जबकि इस एक में, मैंने चीजों को समझाने के लिए एक अलग दृष्टिकोण की कोशिश की। तुम क्या सोचते हो? क्या मुझे अन्य उत्तर को संपादित करना चाहिए और इसको जोड़ना चाहिए? हो सकता है, इसे पहले से बताएं ... पता नहीं! सुझाव के लिए धन्यवाद!
मिगुएल एंजेलो

7

एक अच्छा महामारी मैं हमेशा इस बारे में याद रखता हूं निम्नलिखित है:

यदि अभिव्यक्ति ++के बाद खड़ा होता है , तो यह वह मान लौटाता है जो पहले था । तो निम्न कोड

int a = 1;
int b = a++;

1 है, क्योंकि a1 इससे पहले कि ++खड़े होने के बाद बढ़ गया था a। लोग इस पोस्ट को नोटेशन कहते हैं। एक प्री फिक्स नोटेशन भी है, जहां चीजें बिल्कुल विपरीत हैं: यदि पहले++ खड़ा होता है , तो अभिव्यक्ति उस मान को वापस करती है जो ऑपरेशन के बाद है:

int a = 1;
int b = ++a;

b यहाँ दो है।

तो आपके कोड के लिए, इसका मतलब है

int i = 0;
i += (i++);

i++रिटर्न 0 (जैसा कि ऊपर वर्णित है), इसलिए 0 + 0 = 0

i += (++i); // Here 'i' would become two

स्कॉट मेयर्स "प्रभावी C ++ प्रोग्रामिंग" में उन दो संकेतन के बीच अंतर का वर्णन करते हैं। आंतरिक रूप से, i++(पोस्टफ़िक्स) याद करते मूल्य iथा, और उपसर्ग संकेतन (कॉल ++i,) और पुराने मान देता है i। यही कारण है कि आपको लूप ++iमें उपयोग करना चाहिए for(हालांकि मुझे लगता है कि सभी आधुनिक संकलन लूप में अनुवाद i++कर रहे हैं )।++ifor


1
मैंने परीक्षण किया int i = 0; i += (++i), और iदो के बजाय एक पर सेट है। यह पोस्टफ़िक्स के बजाय उपसर्ग का उपयोग करके तथ्य यह है कि, यदि आप लिखना नहीं बदलता है के बाद से भी मेरी बात समझ में आता है, i += (++i)के लिए बाहर i = i + (++i), iसे पहले मूल्यांकन किया जाता है ++i, जिसका परिणाम i = 0 + (++i)है और अंत में i = 0 + 1
वुत्ज

6

आपके प्रश्न का एकमात्र उत्तर जो सही है: क्योंकि यह अपरिभाषित है।

ठीक है, पहले तुम सब मुझे जला दो ।।

आप सभी ने उत्तर दिया कि i+=i++परिणाम के लिए ठीक और तार्किक क्यों है i=0

मुझे आपके प्रत्येक उत्तर के लिए प्रत्येक 1 वोट देने का लालच दिया गया था, लेकिन मेरे द्वारा गणना की गई प्रतिष्ठा बहुत अधिक होगी।

मैं तुम लोगों पर इतना पागल क्यों हूँ? इस कारण नहीं कि आपके उत्तर क्या बताते हैं ..
मेरा मतलब है, मैंने पढ़ा हर उत्तर असंभव को समझाने का एक उल्लेखनीय प्रयास किया है, आई तालियाँ!

लेकिन नतीजा क्या है ?? क्या यह सहज परिणाम है - क्या यह स्वीकार्य परिणाम है ??

आप में से प्रत्येक ने "नग्न राजा" को देखा और किसी तरह इसे तर्कसंगत राजा के रूप में स्वीकार किया।

आप सभी गलत हैं!

i+=i++;परिणाम 0अपरिभाषित है।

भाषा मूल्यांकन तंत्र में एक बग यदि आप करेंगे .. या इससे भी बदतर! डिजाइन में एक बग।

एक सबूत चाहते हैं? बेशक आप चाहते हैं!

int t=0; int i=0; t+=i++; //t=0; i=1

अब यह ... सहज परिणाम है! क्योंकि हमने पहले इसका मूल्यांकन tएक मूल्य के साथ सौंपा था और मूल्यांकन और असाइनमेंट के बाद ही हमारे पास पोस्ट ऑपरेशन हो रहा था - तर्कसंगत नहीं है?

क्या यह तर्कसंगत है कि: i=i++और i=iउसी परिणाम के लिए उपज i?

जबकि t=i++और के t=iलिए अलग परिणाम है i

पोस्ट ऑपरेशन कुछ ऐसा है जो बयान मूल्यांकन के बाद होना चाहिए।
इसलिए:

int i=0;
i+=i++;

वैसा ही होना चाहिए यदि हमने लिखा है:

int i=0;
i = i + i ++;

और इसलिए:

int i=0;
i= i + i;
i ++;

और इसलिए:

int i=0;
i = i + i;
i = i + 1;

1यदि हम तर्कसंगत सोच के साथ जाते हैं तो कोई भी परिणाम जो भाषा के डिज़ाइन में एक बग या बग को इंगित नहीं करता है - हालांकि MSDN और कई अन्य स्रोत हमें बताते हैं "हे - यह अपरिभाषित है!"

अब, इससे पहले कि मैं जारी रखूं, मेरे द्वारा दिए गए उदाहरणों के इस सेट का भी किसी ने समर्थन या स्वीकार नहीं किया है। हालांकि यह सहज और तर्कसंगत तरीका है।

कोडर को इस बात का कोई ज्ञान नहीं होना चाहिए कि असेंबली को कैसे लिखा या अनुवादित किया जा रहा है!

यदि यह इस तरीके से लिखा गया है जो भाषा की परिभाषा का सम्मान नहीं करेगा - यह एक बग है!

और खत्म करने के लिए मैंने इसे विकिपीडिया, इंक्रीमेंट और डिक्रीमेंट ऑपरेटरों से कॉपी किया :
चूंकि वेतन वृद्धि / वेतन वृद्धि ऑपरेटर अपने ऑपरेंड को संशोधित करता है, इसलिए एक ही अभिव्यक्ति के भीतर एक से अधिक बार ऐसे ऑपरेंड का उपयोग अपरिभाषित परिणाम उत्पन्न कर सकता है । उदाहरण के लिए, एक्स - ++ एक्स जैसे अभिव्यक्तियों में, यह स्पष्ट नहीं है कि घटाव और वेतन वृद्धि ऑपरेटरों को किस क्रम में किया जाना चाहिए। इस तरह की स्थिति तब और भी बदतर हो जाती है जब कंपाइलर द्वारा ऑप्टिमाइज़ेशन लागू किया जाता है, जिसके परिणामस्वरूप ऑपरेशन के निष्पादन के क्रम में प्रोग्रामर के उद्देश्य से भिन्न हो सकते हैं।

और इसीलिए।

सही उत्तर यह है कि यह इस्तेमाल नहीं किया जाना चाहिए! (जैसा कि यह अलग है!)

हां .. - इसके अप्रत्याशित परिणाम हैं, भले ही C # मजबूर किसी भी तरह इसे सामान्य करने की कोशिश कर रहा हो।

मुझे C # भाषा के सामान्य या अच्छी तरह से परिभाषित व्यवहार के रूप में आप सभी के व्यवहार का वर्णन करने वाला कोई भी दस्तावेज़ नहीं मिला। जो मैंने पाया वह ठीक विपरीत है!

[ पोस्टफेड इन्क्रीमेंट और डिक्लेरेशन ऑपरेटर्स के लिए MSDN प्रलेखन से कॉपी किया गया: ++ और - ]

जब किसी फ़ंक्शन तर्क के लिए पोस्टफ़िक्स ऑपरेटर को लागू किया जाता है, तो फ़ंक्शन के पास जाने से पहले तर्क का मान बढ़ा या घटाया जाने की गारंटी नहीं होती है। अधिक जानकारी के लिए C ++ मानक में खंड 1.9.17 देखें।

उन शब्दों की सूचना दें जिनकी गारंटी नहीं है ...

मुझे माफ़ कर दो अगर वह जवाब घमंडी लगता है - मैं एक अभिमानी व्यक्ति नहीं हूँ। मैं सिर्फ यह मानता हूं कि हजारों लोग सीखने के लिए यहां आते हैं और मेरे द्वारा पढ़े गए उत्तर उन्हें गुमराह करेंगे और उनके तर्क और विषय की समझ को नुकसान पहुंचाएंगे।


मुझे यकीन नहीं है कि मैं 100% का पालन कर रहा हूं, लेकिन आप C ++ दस्तावेज़ीकरण का संदर्भ देते हैं, लेकिन मेरा प्रश्न C # के बारे में था। उस पर प्रलेखन यहाँ है
पीटर

मैं अपने उत्तर में C # का उल्लेख कर रहा था। आपके द्वारा दिए गए लिंक से: x ++ या x-- का परिणाम ऑपरेशन से पहले x का मान है, जबकि ++ x या --x का परिणाम ऑपरेशन के बाद x का मूल्य है। या तो मामले में, एक्स ही ऑपरेशन के बाद एक ही मूल्य है। स्पष्ट रूप से पता चलता है कि यह परीक्षण i=++iकरते समय ऐसा नहीं है .. क्योंकि इससे अलग परिणाम मिलेगा i=i++। इसलिए मेरा जवाब खड़ा है।
GY

अहा, ठीक है, लेकिन यह भ्रामक है क्योंकि आप C ++ प्रलेखन का संदर्भ लेते हैं। तो आप क्या कह रहे हैं कि विनिर्देश सही ढंग से लागू नहीं किया गया है?
पीटर

नहीं, जो मैं कह रहा हूं कि यह विनिर्देश के अनुसार अपरिभाषित है, और अपरिभाषित का उपयोग करने से अपरिभाषित परिणाम समाप्त हो जाएंगे।
GY

C ++ में अपरिभाषित, लेकिन C # कहता है कि ऑपरेशन के बाद इसका मूल्य समान होना चाहिए , नहीं? यह अपरिभाषित के समान नहीं है (लेकिन मैं मानता हूं कि आपको इसका उपयोग नहीं करना चाहिए, मेरा अस्वीकरण देखें, मैं सिर्फ यह समझने की कोशिश कर रहा था कि क्या हो रहा है)।
पीटर

4

चर के बाद ++ संचालक इसे पोस्टफिक्स इन्क्रीमेंट बनाता है। वृद्धिशील बयान, जोड़ने और असाइनमेंट में सब कुछ के बाद होता है। यदि इसके बजाय, आप ++ को वेरिएबल से पहले रखते हैं, तो यह i के मान के मूल्यांकन से पहले होगा, और आपको अपेक्षित उत्तर देगा।


2
++ऐसा नहीं होता है के बाद+= बयान, ऐसा होता है के दौरान के निष्पादन के +=बयान। यही कारण है कि के प्रभाव से ++ओवरराइड मिलता है +=
dtb

++ का उपयोग करना वास्तव में 1 में परिणाम देता है, 2 में नहीं (मेरा मूल रूप से 'अपेक्षित उत्तर')।
पीटर

ऐसा लगता है कि असाइनमेंट अभिव्यक्ति में पूर्व या बाद के वेतन वृद्धि के कारण संशोधन को += ओवरराइट करता है।
स्टीवन लू

4

गणना के चरण हैं:

  1. int i=0 // शुरुआत में 0 से
  2. i+=i++ // समीकरण
  3. i=i+i++ // कंपाइलर द्वारा समीकरण को सरल बनाने के बाद
  4. i=0+i++ // i प्रतिस्थापन
  5. i=0+0 // i ++ नीचे जैसा बताया गया है
  6. i=0 // अंतिम परिणाम I = 0

यहाँ, शुरू में मान i0. WKT है, i++कुछ भी नहीं है: पहले iमूल्य का उपयोग करें और फिर iमूल्य में 1. वृद्धि करें । इसलिए यह iमूल्य का उपयोग करता है , 0, गणना करते समय i++और फिर इसे 1 से बढ़ाता है। तो इससे एक मूल्य होता है 0 का।


3

दो विकल्प हैं:

पहला विकल्प: यदि कंपाइलर कथन को निम्नानुसार पढ़ता है,

i++;
i+=i;

फिर परिणाम 2 है।

के लिये

else if
i+=0;
i++;

परिणाम 1 है।


5
जिनमें से कोई भी वास्तविक परिणाम नहीं है।
स्टीवन लू

3

बहुत सावधान रहें: सी एफएक्यू पढ़ें : आप जो करने की कोशिश कर रहे हैं ( ++एक ही चर के मिश्रण का मिश्रण है ) न केवल अनिर्दिष्ट है, बल्कि यह भी अपरिभाषित है (इसका अर्थ है कि मूल्यांकन करने पर कंपाइलर कुछ भी कर सकता है !) "उचित" परिणाम)।

कृपया पढ़ें, खंड 3 । पूरा खंड एक पढ़ने लायक है! विशेष रूप से 3.9, जो अनिर्दिष्ट के निहितार्थ की व्याख्या करता है। धारा 3.3 आपको एक त्वरित सारांश देता है कि आप क्या कर सकते हैं, और "i ++" और इस तरह से नहीं कर सकते।

संकलक इंटर्नल के आधार पर, आपको 0, या 2, या 1, या कुछ और भी मिल सकता है! और जैसा कि यह अपरिभाषित है, ऐसा करना उनके लिए ठीक है।


उफ़, ग # ... मुझे "जीसीसी" द्वारा फेंक दिया गया था कुछ कोड को अलग करने के माध्यम से चले गए।
ओलिवियर दुलैक

1
मुझे याद आया कि यह C # भी था, लेकिन फिर भी जवाब पसंद आया।
Iain Collins

1
@ मुख्य: धन्यवाद, मेरा यह भी मानना ​​है कि यह उत्तर उपलब्ध रखने के लायक था, बहुत से लोग इस बारे में नहीं जानते (या उस महान फ़ाक के बारे में , यूज़नेट के सबसे अच्छे समय से, जहां एक सबजेट पर ज्ञान रखने वाले अधिकांश लोग उसी के लिए जा रहे थे। इसे अपडेट करने का स्थान)
ओलिवियर दुलैक

3

उपरोक्त उत्तरों में बहुत सारे उत्कृष्ट तर्क हैं, मैंने सिर्फ एक छोटा परीक्षण किया और आपके साथ साझा करना चाहता हूं

int i = 0;
i+ = i++;

यहाँ परिणाम मैं 0 परिणाम दिखा रहा है। अब नीचे के मामलों पर विचार करें:

मामला एक:

i = i++ + i; //Answer 1

पहले मैंने सोचा था कि उपरोक्त कोड पहली नज़र के उत्तर के समान है, और वास्तव में इस एक के लिए i का उत्तर 1 है।

केस 2:

i = i + i++; //Answer 0 this resembles the question code.

यहाँ वेतन वृद्धि संचालक निष्पादन पथ में नहीं आता है, पिछले मामले के विपरीत जहाँ i ++ के अलावा निष्पादन से पहले मौका है।

मुझे आशा है इससे कुछ मदद मिलेगी। धन्यवाद


2

सी प्रोग्रामिंग 101 प्रकार के दृष्टिकोण से इसका जवाब देने की उम्मीद है।

मुझे लगता है जैसे यह इस क्रम में हो रहा है:

  1. i0 के रूप में मूल्यांकन किया जाता है, जिसके परिणामस्वरूप i = 0 + 0वेतन वृद्धि i++"पंक्तिबद्ध" होती है, लेकिन 0 का असाइनमेंट iअभी तक नहीं हुआ है।
  2. वेतन वृद्धि i++होती है
  3. i = 0ऊपर से असाइनमेंट होता है, प्रभावी रूप से # 2 (पोस्ट-इन्क्रीमेंट) के दौरान कुछ भी ओवरराइट करने पर।

अब, # 2 वास्तव में कभी नहीं हो सकता है (शायद नहीं?) क्योंकि संकलक को पता चलता है कि यह कोई उद्देश्य नहीं होगा, लेकिन यह बॉयलर पर निर्भर हो सकता है। किसी भी तरह से, अन्य, अधिक जानकार जवाबों से पता चला है कि परिणाम सही है और सी # मानक के अनुरूप है, लेकिन यह परिभाषित नहीं है कि सी / सी ++ के लिए यहां क्या होता है।

कैसे और क्यों मेरी विशेषज्ञता से परे है, लेकिन तथ्य यह है कि पूर्व-दाहिने-साइड के असाइनमेंट का मूल्यांकन पोस्ट-इंक्रीमेंट के बाद होता है, शायद यहाँ क्या भ्रमित है।

इसके अलावा, आप परिणाम की अपेक्षा नहीं करेंगे जब तक कि आप मेरे विश्वास के ++iबजाय जब तक आप ऐसा नहीं i++करेंगे।


1
Preincrement संस्करण 2C ++: ideone.com/8dH8tf
Steven Lu

यह समझ आता है। लेकिन प्री-इंक्रीमेंट पोस्ट-इंक्रीमेंट की तुलना में थोड़ी कम जटिल स्थिति है।
gkimsey

2

सीधे शब्दों में कहें,

i ++, "+ =" ऑपरेटर पूरा होने के बाद 1 "i" जोड़ देगा।

आप जो चाहते हैं, वह ++ i है, जिससे कि "+ =" ऑपरेटर निष्पादित होने से पहले यह 1 से "i" जोड़ देगा।


0
i=0

i+=i

i=i+1

i=0;

फिर 1 को जोड़ा जाता है i

मैं + = मैं ++

तो करने के लिए 1 जोड़ने से पहले i, iकेवल अगर हम 1 से पहले जोड़ने 0. का मूल्य ले लिया, iमान 0 मिलता है।

i+=++i

i=2

-4

उत्तर iहोगा 1

आइए नजर डालते हैं कैसे:

शुरू में i=0;

फिर जब i +=i++;हम मूल्य के अनुसार गणना करेंगे तो कुछ ऐसा होगा 0 +=0++;, इसलिए ऑपरेटर के अनुसार पूर्ववर्तीता 0+=0पहले प्रदर्शन करेगी और परिणाम होगा 0

फिर वेतन वृद्धि ऑपरेटर के रूप में 0++, के रूप में लागू होगा 0+1और iहोगा 1


3
यह उत्तर गलत है। आपको 1 नहीं मिलेगा क्योंकि जब आप 0 += 0++;असाइनमेंट करते हैं तो वेतन वृद्धि के बाद ++लेकिन मैं ++(क्योंकि एक पोस्ट ऑपरेटर के रूप में व्याख्या की गई है) के मूल्य के साथ
फोनिक्स

2
क्षमा करें, लेकिन यह गलत है। मेरे सवाल पढ़ें और आप मुझे कहना परिणाम 0. आप कोड चलाते हैं, तो आप इसे देखेंगे देखेंगे प्रभावी रूप से 0. है
पीटर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.