I = (i, ++ i, 1) + 1 क्या करता है; करना?


174

अपरिभाषित व्यवहार और अनुक्रम बिंदुओं के बारे में इस उत्तर को पढ़ने के बाद , मैंने एक छोटा कार्यक्रम लिखा:

#include <stdio.h>

int main(void) {
  int i = 5;
  i = (i, ++i, 1) + 1;
  printf("%d\n", i);
  return 0;
}

आउटपुट है 2। हे भगवान, मैं कमी नहीं देख रहा था! यहाँ क्या हो रहा है?

इसके अलावा, उपरोक्त कोड को संकलित करते समय, मुझे एक चेतावनी मिली:

px.c: 5: 8: चेतावनी: अल्पविराम अभिव्यक्ति के बाएं हाथ का कोई प्रभाव नहीं है

  [-Wunused-value]   i = (i, ++i, 1) + 1;
                        ^

क्यों? लेकिन शायद यह मेरे पहले प्रश्न के उत्तर से स्वतः ही मिल जाएगा।


289
अजीब बातें मत करो, आपके पास कोई दोस्त नहीं होगा :(
Maroun

9
चेतावनी संदेश आपके पहले प्रश्न का उत्तर है।
यू हाओ

2
@gsamaras: नहींं। परिणामी मूल्य को छोड़ दिया जाता है, संशोधन नहीं। वास्तविक उत्तर: अल्पविराम ऑपरेटर एक अनुक्रम बिंदु बनाता है।
कारोली होर्वाथ

3
@gsamaras आपको तब ध्यान नहीं देना चाहिए जब आपके पास सकारात्मक अंक और 10+ से अधिक प्रश्न हों।
LyingOnTheSky

9
नोट: एक अनुकूलन कंपाइलर सरल कर सकता हैprintf("2\n");
chux -

जवाबों:


256

अभिव्यक्ति में (i, ++i, 1), इस्तेमाल किया गया अल्पविराम अल्पविराम ऑपरेटर है

अल्पविराम ऑपरेटर (टोकन द्वारा दर्शाया गया ,) एक बाइनरी ऑपरेटर है जो अपने पहले ऑपरेंड का मूल्यांकन करता है और परिणाम को छोड़ देता है, और फिर दूसरे ऑपरेंड का मूल्यांकन करता है और इस मान (और प्रकार) को लौटाता है।

क्योंकि यह अपने पहले ऑपरेंड को छोड़ देता है, यह आम तौर पर केवल उपयोगी होता है जहां पहले ऑपरेंड में वांछनीय दुष्प्रभाव होते हैं । यदि पहले ऑपरेंड का साइड इफेक्ट नहीं होता है, तो कंपाइलर बिना किसी प्रभाव के अभिव्यक्ति के बारे में चेतावनी उत्पन्न कर सकता है।

तो, उपरोक्त अभिव्यक्ति में, सबसे बाईं ओर iका मूल्यांकन किया जाएगा और इसके मूल्य को छोड़ दिया जाएगा। फिर ++iमूल्यांकन किया जाएगा और i1 से वृद्धि होगी और फिर से अभिव्यक्ति के मूल्य को ++iछोड़ दिया जाएगा, लेकिन इसका साइड इफेक्ट iस्थायी है । फिर 1मूल्यांकन किया जाएगा और अभिव्यक्ति का मूल्य होगा 1

के बराबर है

i;          // Evaluate i and discard its value. This has no effect.
++i;        // Evaluate i and increment it by 1 and discard the value of expression ++i
i = 1 + 1;  

ध्यान दें कि उपरोक्त अभिव्यक्ति पूरी तरह से वैध है और अपरिभाषित व्यवहार को लागू नहीं करती है क्योंकि अल्पविराम ऑपरेटर के बाएं और दाएं ऑपरेंड के मूल्यांकन के बीच एक अनुक्रम बिंदु है


1
हालांकि अंतिम अभिव्यक्ति वैध है, दूसरी अभिव्यक्ति ++ मैं एक अपरिभाषित व्यवहार नहीं है? इसका मूल्यांकन किया जाता है और असिंचित वैरिएबल का मान पूर्व-संवर्धित होता है, जो सही नहीं है? या क्या मैं कुछ न कुछ भूल रहा हूं?
कौशिक शेट्टी

2
@Koushik; iके साथ आरंभ किया गया है 5। डिक्लेरेशन स्टेटमेंट देखें int i = 5;
haccks

1
मेरी गलती है। क्षमा करें, मैं ईमानदारी से यह देख सकता हूं।
कौशिक शेट्टी

यहाँ एक गलती है: ++ मैं वेतन वृद्धि करूँगा, फिर मैं इसका मूल्यांकन करूँगा, जबकि i ++ मैं मूल्यांकन करूँगा फिर इसे बढ़ाऊँगा।
क्वेंटिन ह्योट

1
@QuentinHayot; क्या? अभिव्यक्ति के मूल्यांकन के बाद कोई भी दुष्प्रभाव होता है। इस स्थिति में ++i, इस अभिव्यक्ति का मूल्यांकन किया iजाएगा , वृद्धि की जाएगी और यह वेतन वृद्धि अभिव्यक्ति का मूल्य होगा। के मामले में i++, इस अभिव्यक्ति का मूल्यांकन किया जाएगा, पुराने मूल्य की iअभिव्यक्ति का मूल्य iहोगा , अभिव्यक्ति के पिछले और अगले अनुक्रम बिंदु के बीच किसी भी समय वेतन वृद्धि होगी।
haccks

62

C11अध्याय 6.5.17, कोमा संचालक से उद्धृत

अल्पविराम ऑपरेटर के बाएं संचालक का मूल्यांकन एक व्यंजक अभिव्यक्ति के रूप में किया जाता है; इसके मूल्यांकन और सही ऑपरेंड के बीच एक अनुक्रम बिंदु है। फिर सही ऑपरेंड का मूल्यांकन किया जाता है; परिणाम का अपना प्रकार और मूल्य होता है।

तो, आपके मामले में,

(i, ++i, 1)

के रूप में मूल्यांकन किया है

  1. i, शून्य अभिव्यक्ति के रूप में मूल्यांकन किया जाता है, मूल्य त्याग दिया गया
  2. ++i, शून्य अभिव्यक्ति के रूप में मूल्यांकन किया जाता है, मूल्य त्याग दिया गया
  3. अंत में 1, मान लौटा।

तो, अंतिम कथन जैसा दिखता है

i = 1 + 1;

और iहो जाता है 2। मुझे लगता है कि यह आपके दोनों सवालों के जवाब देता है,

  • iमान 2 कैसे मिलता है?
  • चेतावनी संदेश क्यों है?

नोट: एफडब्ल्यूआईडब्ल्यू, जैसा कि बाएं हाथ के संचालन के मूल्यांकन के बाद एक अनुक्रम बिंदु मौजूद है, एक अभिव्यक्ति (i, ++i, 1)यूबी को आमंत्रित नहीं करेगी, जैसा कि आम तौर पर गलती से हो सकता है।


+1 सौरव, क्योंकि यह बताता है कि क्यों iस्पष्ट रूप से गहनता का कोई प्रभाव नहीं है! हालांकि, मुझे नहीं लगता कि यह उस आदमी के लिए इतना स्पष्ट था जो अल्पविराम ऑपरेटर को नहीं जानता है (और मुझे नहीं पता था कि मदद के लिए कैसे खोज करें, सवाल पूछने के अलावा)। दया मुझे बहुत सारे डाउनवोट मिले! मैं अन्य उत्तरों की जांच करूंगा और फिर तय करूंगा कि किसे स्वीकार करना है। धन्यवाद! अच्छा शीर्ष उत्तर btw।
gsamaras

मुझे लगता है कि मुझे यह समझाना होगा कि मैंने उत्तर को क्यों स्वीकार किया। मैं तुम्हारा स्वीकार करने के लिए तैयार था, क्योंकि यह वास्तव में मेरे दोनों सवालों का जवाब है। हालाँकि, यदि आप मेरे प्रश्न की टिप्पणियों की जाँच करते हैं, तो आप देखेंगे कि कुछ लोग पहली नज़र में यह नहीं देख सकते हैं कि यह यूबी को क्यों लागू नहीं करता है। haccks जवाब कुछ प्रासंगिक जानकारी प्रदान करते हैं। बेशक, मेरे पास मेरे सवाल में यूबी से जुड़ा हुआ जवाब है, लेकिन कुछ लोगों को यह याद आ सकता है। आशा है कि आप मेरी इस इच्छा से सहमत हैं, यदि मुझे नहीं बताया जाए। :)
gsamaras

30
i = (i, ++i, 1) + 1;

आइए इसका विश्लेषण चरण दर चरण करें।

(i,   // is evaluated but ignored, there are other expressions after comma
++i,  // i is updated but the resulting value is ignored too
1)    // this value is finally used
+ 1   // 1 is added to the previous value 1

तो हम प्राप्त करते हैं 2. और अब अंतिम काम:

i = 2;

इससे पहले कि यह अब अधिलेखित कर दिया गया था मैं जो कुछ भी था ।


यह बताना अच्छा होगा कि अल्पविराम ऑपरेटर के कारण ऐसा होता है। हालांकि कदम विश्लेषण द्वारा कदम के लिए +1! अच्छा शीर्ष उत्तर btw।
gsamaras

मुझे अपर्याप्त स्पष्टीकरण के लिए खेद है, मेरे पास वहां केवल एक नोट है ( ... लेकिन अनदेखा किया गया, वहाँ हैं ... )। मैं मुख्य रूप से यह समझाना चाहता था ++iकि परिणाम में योगदान क्यों नहीं होता।
dlask

अब मेरे छोरों के लिए हमेशा की तरह होगाint i = 0; for( ;(++i, i<max); )
CoffeDeveloper

19

का नतीजा

(i, ++i, 1)

है

1

के लिये

(i,++i,1) 

मूल्यांकन ऐसा होता है कि ,ऑपरेटर मूल्यांकन किए गए मूल्य को छोड़ देता है और जो सही मान है उसे ही बनाए रखेगा1

इसलिए

i = 1 + 1 = 2

1
हाँ, मैंने भी ऐसा सोचा था, लेकिन मुझे नहीं पता कि क्यों!
gsamaras

@gsamaras क्योंकि अल्पविराम ऑपरेटर पिछले शब्द का मूल्यांकन करता है, लेकिन इसे छोड़ देता है (यानी असाइनमेंट या इस तरह के लिए इसका उपयोग नहीं करता है)
Marco A.

14

आपको कॉमा ऑपरेटर के लिए विकी पेज पर कुछ अच्छा पढ़ने को मिलेगा ।

मूल रूप से, यह

... अपने पहले ऑपरेंड का मूल्यांकन करता है और परिणाम को छोड़ देता है, और फिर दूसरे ऑपरेंड का मूल्यांकन करता है और इस मान (और प्रकार) को लौटाता है।

इस का मतलब है कि

(i, i++, 1)

बदले में, मूल्यांकन करना i, परिणाम को त्यागना, मूल्यांकन करना i++, परिणाम को त्यागना और फिर मूल्यांकन करना और वापस आना 1


O_O नरक, क्या वह वाक्य रचना C ++ में मान्य है, मुझे याद है कि मेरे पास कुछ ऐसे स्थान थे जहाँ मुझे उस वाक्यविन्यास की आवश्यकता थी (मूल रूप से मैंने लिखा था: (void)exp; a= exp2;जबकि मुझे बस आवश्यकता थी a = exp, exp2;)
CoffeDveloper

13

आपको यह जानना होगा कि अल्पविराम ऑपरेटर यहां क्या कर रहा है:

आपकी अभिव्यक्ति:

(i, ++i, 1)

पहली अभिव्यक्ति, iमूल्यांकन किया जाता है, दूसरी अभिव्यक्ति, ++iमूल्यांकन किया जाता है, और तीसरी अभिव्यक्ति, 1पूरी अभिव्यक्ति के लिए लौटा दी जाती है।

तो परिणाम है: i = 1 + 1

आपके बोनस प्रश्न के लिए, जैसा कि आप देखते हैं, पहली अभिव्यक्ति iका कोई प्रभाव नहीं पड़ता है, इसलिए कंपाइलर शिकायत करता है।


5

कॉमा की एक 'उलटा' मिसाल है। यह वही है जो आपको आईबीएम (70/80) से पुरानी पुस्तकों और सी मैनुअल से मिलेगा। तो अंतिम 'कमांड' वह है जो अभिभावक की अभिव्यक्ति में प्रयोग किया जाता है।

आधुनिक C में इसका उपयोग अजीब है लेकिन पुराने C (ANSI) में बहुत दिलचस्प है:

do { 
    /* bla bla bla, consider conditional flow with several continue's */
} while ( prepAnything(), doSomethingElse(), logic_operation);

जबकि सभी कार्यों (कार्यों) को बाएं से दाएं कहा जाता है, केवल अंतिम अभिव्यक्ति का उपयोग सशर्त 'जबकि' के परिणामस्वरूप किया जाएगा। यह 'गोटो'स को हैंडल करने से रोकता है ताकि कंडीशन चेक करने से पहले कमांड का यूनीक ब्लॉक रखा जा सके।

EDIT: यह एक हैंडलिंग फ़ंक्शन को कॉल से भी बचता है जो बाएं ऑपरेंड पर सभी लॉजिक का ध्यान रख सकता है और इसलिए तार्किक परिणाम लौटाता है। याद रखें कि, सी। के अतीत में हमारे पास इनलाइन फ़ंक्शन नहीं था, इसलिए यह कॉल ओवरहेड से बच सकता है।


लुसियानो, आपको इस उत्तर का लिंक भी मिला: stackoverflow.com/questions/17902992/…
gsamaras

इनलाइन फ़ंक्शंस से पहले 90 के दशक की शुरुआत में, मैंने कोड को व्यवस्थित और अनुकूलित करने के लिए इसका बहुत उपयोग किया।
लुसियानो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.