c++ - अपरिभाषित व्यवहार और अनुक्रम बिंदु




undefined-behavior c++-faq (3)

सी ++ 98 और सी ++ 03

यह उत्तर C ++ मानक के पुराने संस्करणों के लिए है। मानक के सी ++ 11 और सी ++ 14 संस्करण औपचारिक रूप से 'अनुक्रम बिंदु' नहीं होते हैं; संचालन 'अनुक्रमित' या 'अपूर्ण' या 'अनिश्चित रूप से अनुक्रमित' हैं। शुद्ध प्रभाव अनिवार्य रूप से वही है, लेकिन शब्दावली अलग है।

अस्वीकरण : ठीक है। यह जवाब थोड़ा लंबा है। तो इसे पढ़ने के दौरान धैर्य रखें। यदि आप पहले से ही इन चीजों को जानते हैं, तो उन्हें फिर से पढ़ना आपको पागल नहीं बनायेगा।

पूर्व-आवश्यकताएं : सी ++ मानक का प्राथमिक ज्ञान

अनुक्रम अंक क्या हैं?

मानक कहते हैं

निष्पादन अनुक्रम में कुछ निर्दिष्ट बिंदुओं पर अनुक्रम बिंदु कहा जाता है , पिछले मूल्यांकन के सभी दुष्प्रभाव पूर्ण हो जाएंगे और बाद के मूल्यांकनों का कोई दुष्प्रभाव नहीं होगा। (§1.9 / 7)

दुष्प्रभाव? दुष्प्रभाव क्या हैं?

अभिव्यक्ति का मूल्यांकन कुछ उत्पन्न करता है और यदि इसके अलावा निष्पादन पर्यावरण की स्थिति में कोई बदलाव होता है तो यह कहा जाता है कि अभिव्यक्ति (इसके मूल्यांकन) के कुछ दुष्प्रभाव होते हैं।

उदाहरण के लिए:

int x = y++; //where y is also an int

प्रारंभिक ऑपरेशन के अलावा ++ ऑपरेटर के साइड इफेक्ट के कारण y का मान बदल जाता है।

अब तक सब ठीक है। अनुक्रम बिंदुओं पर आगे बढ़ना। Comp.lang.c लेखक Steve Summit द्वारा दिए गए सीक-पॉइंट की एक वैकल्पिक परिभाषा:

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

सी ++ मानक में सूचीबद्ध सामान्य अनुक्रम बिंदु क्या हैं?

वो है:

  • पूर्ण अभिव्यक्ति के मूल्यांकन के अंत में ( §1.9/16 ) (एक पूर्ण अभिव्यक्ति एक अभिव्यक्ति है जो किसी अन्य अभिव्यक्ति का उप-अभिव्यक्ति नहीं है।) 1

उदाहरण :

int a = 5; // ; is a sequence point here
  • पहली अभिव्यक्ति ( §1.9/18 ) 2 के मूल्यांकन के बाद निम्नलिखित में से प्रत्येक अभिव्यक्ति के मूल्यांकन में

    • a && b (§5.14)
    • a || b (§5.15)
    • a ? b : c (§5.16)
    • a , b (§5.18) (यहां ए, बी एक अल्पविराम ऑपरेटर है; func(a,a++) , अल्पविराम ऑपरेटर नहीं है, यह तर्क और a++ बीच केवल एक विभाजक है। इस प्रकार व्यवहार उस मामले में अपरिभाषित है (यदि a आदिम प्रकार माना जाता है))
  • फ़ंक्शन बॉडी ( §1.9/17 ) में किसी भी अभिव्यक्ति या कथन के निष्पादन से पहले सभी फ़ंक्शन तर्क (यदि कोई हो) के मूल्यांकन के बाद फ़ंक्शन कॉल (चाहे फ़ंक्शन इनलाइन है) पर।

1: नोट: पूर्ण अभिव्यक्ति के मूल्यांकन में उप-अभिव्यक्तियों का मूल्यांकन शामिल हो सकता है जो पूर्ण अभिव्यक्ति का स्पष्ट रूप से हिस्सा नहीं हैं। उदाहरण के लिए, डिफ़ॉल्ट तर्क अभिव्यक्तियों (8.3.6) का मूल्यांकन करने में शामिल उप-अभिव्यक्तियों को अभिव्यक्ति में बनाया जाता है जो फ़ंक्शन को कॉल करता है, अभिव्यक्ति नहीं जो डिफ़ॉल्ट तर्क को परिभाषित करता है

2: संकेतक संकेतित हैं कि खंड 5 में वर्णित अंतर्निहित ऑपरेटर हैं। जब इन ऑपरेटरों में से एक वैध संदर्भ में अधिभारित (खंड 13) है, इस प्रकार उपयोगकर्ता द्वारा परिभाषित ऑपरेटर फ़ंक्शन को निर्दिष्ट करते हुए, अभिव्यक्ति फ़ंक्शन आमंत्रण को निर्दिष्ट करती है और ऑपरेंड एक तर्क सूची बनाते हैं, उनके बीच एक अंतर्निहित अनुक्रम बिंदु के बिना।

अपरिभाषित व्यवहार क्या है?

मानक धारा §1.3.12 रूप में अपरिभाषित व्यवहार को परिभाषित करता है

व्यवहार, जैसे किसी गलत प्रोग्राम निर्माण या गलत डेटा के उपयोग पर उत्पन्न हो सकता है, जिसके लिए यह अंतर्राष्ट्रीय मानक कोई आवश्यकता नहीं लगाता है 3

अनिश्चित व्यवहार की भी उम्मीद की जा सकती है जब यह अंतर्राष्ट्रीय मानक व्यवहार की किसी भी स्पष्ट परिभाषा के वर्णन को छोड़ देता है।

3: अनुमोदित अपरिभाषित व्यवहार, अप्रत्याशित परिणामों के साथ पूरी तरह से स्थिति को अनदेखा करने से, अनुवाद या निष्पादन को समाप्त करने के लिए पर्यावरण की विशेषता (एक नैदानिक ​​संदेश जारी करने के साथ) के दस्तावेज तरीके से अनुवाद या प्रोग्राम निष्पादन के दौरान व्यवहार करने के लिए होता है। (एक नैदानिक ​​संदेश जारी करने के साथ)।

संक्षेप में, अपरिभाषित व्यवहार का मतलब है कि आपकी नाक से बाहर निकलने वाले डेमन्स से आपकी गर्लफ्रेंड गर्भवती होने पर कुछ भी हो सकता है।

अपरिभाषित व्यवहार और अनुक्रम अंक के बीच संबंध क्या है?

इससे पहले कि आप इसमें शामिल हों, आपको अपरिभाषित व्यवहार, अनिर्दिष्ट व्यवहार और कार्यान्वयन परिभाषित व्यवहार के बीच अंतर (ओं) पता होना चाहिए।

आपको यह भी पता होना चाहिए कि the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified

उदाहरण के लिए:

int x = 5, y = 6;

int z = x++ + y++; //it is unspecified whether x++ or y++ will be evaluated first.

here एक और उदाहरण।

अब §5/4 में मानक कहते हैं

  • 1) पिछले और अगले अनुक्रम बिंदु के बीच एक स्केलर ऑब्जेक्ट में अभिव्यक्ति के मूल्यांकन द्वारा एक बार में संग्रहीत मूल्य संशोधित किया जाएगा।

इसका क्या मतलब है?

अनौपचारिक रूप से इसका मतलब है कि दो अनुक्रम बिंदुओं के बीच एक चर को एक से अधिक बार संशोधित नहीं किया जाना चाहिए। एक अभिव्यक्ति कथन में, next sequence point आमतौर पर समाप्ति अर्धविराम पर होता है, और previous sequence point पिछले कथन के अंत में होता है। एक अभिव्यक्ति में मध्यवर्ती sequence points भी हो सकते हैं।

उपरोक्त वाक्य से निम्नलिखित अभिव्यक्ति अनिर्धारित व्यवहार का आह्वान करते हैं:

i++ * ++i;   // UB, i is modified more than once btw two SPs
i = ++i;     // UB, same as above
++i = 2;     // UB, same as above
i = ++i + 1; // UB, same as above
++++++i;     // UB, parsed as (++(++(++i)))

i = (i, ++i, ++i); // UB, there's no SP between `++i` (right most) and assignment to `i` (`i` is modified more than once btw two SPs)

लेकिन निम्नलिखित अभिव्यक्ति ठीक हैं:

i = (i, ++i, 1) + 1; // well defined (AFAIK)
i = (++i, i++, i);   // well defined 
int j = i;
j = (++i, i++, j*i); // well defined
  • 2) इसके अलावा, पूर्व मान केवल संग्रहीत करने के मूल्य को निर्धारित करने के लिए उपयोग किया जाएगा।

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

उदाहरण के लिए i = i + 1 सभी की पहुंच (एलएचएस और आरएचएस में) सीधे लिखे जाने वाले मान की गणना में शामिल होती है। तो यह ठीक है।

यह नियम प्रभावी रूप से उन लोगों के लिए कानूनी अभिव्यक्तियों को बाधित करता है जिनमें प्रदर्शन के पहले प्रदर्शन से पहले पहुंच होती है।

उदाहरण 1:

std::printf("%d %d", i,++i); // invokes Undefined Behaviour because of Rule no 2

उदाहरण 2:

a[i] = i++ // or a[++i] = i or a[i++] = ++i etc

अस्वीकृत है क्योंकि i ( i a[i] में से a[i] ) के मूल्य में से किसी एक के साथ कुछ भी नहीं करना है जो i (जो i++ में होता है) में संग्रहीत होता है, और इसलिए परिभाषित करने का कोई अच्छा तरीका नहीं है-- या तो हमारी समझ या संकलक के लिए - क्या बढ़ी हुई मान को संग्रहीत करने से पहले या उसके बाद पहुंच होनी चाहिए। तो व्यवहार अपरिभाषित है।

उदाहरण 3:

int x = i + i++ ;// Similar to above

here जवाब here पालन here

"अनुक्रम बिंदु" क्या हैं?

अपरिभाषित व्यवहार और अनुक्रम बिंदुओं के बीच संबंध क्या है?

मैं अक्सर मजाकिया और घुलनशील अभिव्यक्तियों का उपयोग करता हूं जैसे a[++i] = i; , खुद को बेहतर महसूस करने के लिए। मुझे उनका उपयोग क्यों करना बंद कर देना चाहिए?

यदि आपने इसे पढ़ लिया है, तो फॉलो-अप प्रश्न अपरिभाषित व्यवहार और अनुक्रम बिंदुओं को पुनः लोड करने के लिए सुनिश्चित रहें

(नोट: यह स्टैक ओवरफ्लो के सी ++ एफएक्यू में प्रवेश करने के लिए है । यदि आप इस फॉर्म में एक एफएक्यू प्रदान करने के विचार की आलोचना करना चाहते हैं, तो मेटा पर पोस्ट करना जो यह सब शुरू कर देगा, ऐसा करने का स्थान होगा। उस प्रश्न की निगरानी सी ++ चैटरूम में की जाती है, जहां एफएक्यू विचार पहली जगह शुरू हुआ था, इसलिए आपके उत्तर को उन लोगों द्वारा पढ़ा जाने की संभावना है जो इस विचार के साथ आए थे।)


मुझे लगता है कि परिवर्तन के लिए एक मौलिक कारण है, यह पुरानी व्याख्या को स्पष्ट करने के लिए केवल कॉस्मेटिक नहीं है: यही कारण समरूपता है। विस्तार का निर्दिष्ट आदेश केवल कई संभावित धारावाहिक क्रमों में से एक का चयन है, यह आदेशों के पहले और बाद में काफी अलग है, क्योंकि यदि कोई निर्दिष्ट आदेश नहीं है, समवर्ती मूल्यांकन संभव है: पुराने नियमों के साथ ऐसा नहीं। उदाहरण के लिए:

f (a,b)

पहले या तो एक बी, या, बी तो ए। अब, ए और बी का मूल्यांकन अंतःस्थापित या यहां तक ​​कि विभिन्न कोरों पर भी किया जा सकता है।


सी ++ 17 ( N4659 9) में एक प्रस्ताव शामिल है जिसमें N4659 सी ++ के लिए अभिव्यक्ति अभिव्यक्ति मूल्यांकन आदेश शामिल है जो अभिव्यक्ति मूल्यांकन के एक कठोर क्रम को परिभाषित करता है।

विशेष रूप से, निम्नलिखित वाक्य जोड़ा गया था:

8.18 असाइनमेंट और कंपाउंड असाइनमेंट ऑपरेटर :
....

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

यह पहले अनिर्धारित व्यवहार के कई मामलों को वैध बनाता है, जिसमें एक प्रश्न भी शामिल है:

a[++i] = i;

हालांकि कई अन्य समान मामले अभी भी अपरिभाषित व्यवहार का कारण बनते हैं।

N4140 :

i = i++ + 1; // the behavior is undefined

लेकिन N4659

i = i++ + 1; // the value of i is incremented
i = i++ + i; // the behavior is undefined

बेशक, एक सी ++ 17 अनुपालन कंपाइलर का उपयोग करने का मतलब यह नहीं है कि किसी को ऐसे अभिव्यक्ति लिखना शुरू करना चाहिए।







sequence-points