सी ++ 98 और सी ++ 03
यह उत्तर C ++ मानक के पुराने संस्करणों के लिए है। मानक के C ++ 11 और C ++ 14 संस्करणों में औपचारिक रूप से 'अनुक्रम बिंदु' नहीं हैं; इसके बजाय 'अनुक्रमित' या 'निष्कासित' या 'अनिश्चित अनुक्रमण' से पहले संचालन किया जाता है। शुद्ध प्रभाव अनिवार्य रूप से एक ही है, लेकिन शब्दावली अलग है।
अस्वीकरण : ठीक है। यह उत्तर थोड़ा लंबा है। इसलिए इसे पढ़ते समय धैर्य रखें। यदि आप पहले से ही इन चीजों को जानते हैं, तो उन्हें फिर से पढ़ना आपको पागल नहीं करेगा।
पूर्व-आवश्यकताएं : C ++ मानक का एक प्राथमिक ज्ञान
अनुक्रम अंक क्या हैं?
मानक कहते हैं
निष्पादन बिंदुओं में कुछ निर्दिष्ट बिंदुओं पर अनुक्रम बिंदु कहा जाता है , पिछले मूल्यांकन के सभी दुष्प्रभाव पूर्ण होंगे और बाद के मूल्यांकन के कोई दुष्प्रभाव नहीं हुए होंगे। (§1.9 / 7)
दुष्प्रभाव? साइड इफेक्ट्स क्या हैं?
एक अभिव्यक्ति का मूल्यांकन कुछ पैदा करता है और अगर इसके अलावा निष्पादन वातावरण की स्थिति में बदलाव होता है, तो यह कहा जाता है कि अभिव्यक्ति (इसके मूल्यांकन) का कुछ दुष्प्रभाव है।
उदाहरण के लिए:
int x = y++; //where y is also an int
इनिशियलाइज़ेशन ऑपरेशन के अलावा ऑपरेटर y
के साइड इफेक्ट के कारण मूल्य में परिवर्तन होता है ++
।
अब तक सब ठीक है। अनुक्रम बिंदुओं पर आगे बढ़ना। Comp.lang.c लेखक द्वारा दिए गए seq-points की एक वैकल्पिक परिभाषा Steve Summit
:
अनुक्रम बिंदु समय का एक बिंदु है जिस पर धूल जम गई है और अब तक देखे गए सभी दुष्प्रभाव पूर्ण होने की गारंटी है।
C ++ मानक में सूचीबद्ध सामान्य अनुक्रम बिंदु क्या हैं?
वो है:
पूर्ण अभिव्यक्ति (के मूल्यांकन के अंत में §1.9/16
) (एक पूर्ण अभिव्यक्ति एक अभिव्यक्ति है कि एक और अभिव्यक्ति का एक उपसूचक नहीं है।) 1
उदाहरण :
int a = 5; // ; is a sequence point here
पहली अभिव्यक्ति के मूल्यांकन के बाद निम्न में से प्रत्येक के मूल्यांकन में ( 2§1.9/18
)
a && b (§5.14)
a || b (§5.15)
a ? b : c (§5.16)
a , b (§5.18)
(यहां a, b एक अल्पविराम ऑपरेटर है; अल्पविराम ऑपरेटर func(a,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.
एक और उदाहरण यहाँ ।
अब मानक §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
के सभी पहुँच i
(एलएचएस में और आरएचएस में) कर रहे हैं सीधे गणना में शामिल मूल्य लिखा होना चाहिए की। तो ठीक है।
यह नियम प्रभावी ढंग से उन जिसमें पहुंच प्रमाण्य संशोधन पूर्व में होना करने के लिए कानूनी भाव रोकें।
उदाहरण 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
से एक (में a[i]
) का उस मूल्य से कोई लेना-देना नहीं है जो अंत में स्टोर किया जा रहा है, जो कि i में होता है (जो खत्म हो जाता है i++
), और इसलिए इसे परिभाषित करने का कोई अच्छा तरीका नहीं है - या तो हमारी समझ के लिए या संकलक की - चाहे बढ़े हुए मूल्य को संग्रहीत करने से पहले या बाद में पहुंच होनी चाहिए। अतः व्यवहार अपरिभाषित है।
उदाहरण 3:
int x = i + i++ ;// Similar to above
C ++ 11 के उत्तर का पालन करें ।
*p++ = 4
अपरिभाषित व्यवहार नहीं है।*p++
के रूप में व्याख्या की है*(p++)
।p++
रिटर्नp
(एक प्रति) और पिछले पते पर संग्रहीत मूल्य। वह यूबी क्यों लागू करेगा? यह पूरी तरह से ठीक है।