2012-03-04 6 views
16

कई दिलचस्प here उठाया सवाल सी में अपरिभाषित व्यवहार उनमें से एक (थोड़ा संशोधित) हैक्या 'एक [i] = i;' हमेशा अच्छी तरह से परिभाषित व्यवहार में परिणाम?

के बारे में कर रहे हैं अपरिभाषित व्यवहार में कोड परिणाम का निम्न भाग करता है?

int i = 0, *a = &i; // Line 1 
a[i] = i + 1;   // Line 2 

के बाद से वहाँ प्रश्न के इस हिस्से के लिए कोई ठोस जवाब है, और मैं सी ++ में व्यवहार में जानने में दिलचस्पी रहा हूँ, मैं इसे फिर से यहां की परवरिश कर रहा हूँ।


नियम # 2 Undefined Behavior and Sequence Points से कहते हैं

इसके अलावा, पहले मूल्य तभी पहुँचा दी जाएगी मूल्य निर्धारित करने

ऊपर के उदाहरण में

जाहिर संग्रहीत करने के लिए, मान है दो बार एक्सेस किया जा रहा है: a[i] (lhs) और i (rhs), और उनमें से केवल एक (rhs) मान को संग्रहीत करने के लिए निर्धारित करता है।

क्या लाइन 2 उपर्युक्त नियम का उल्लंघन करता है और परिणामस्वरूप सी ++ 03 में अपरिभाषित व्यवहार होता है?


रूप i लाइन 2 पर संशोधित किया गया है कि क्या करने के लिए कुछ भ्रम की स्थिति नहीं है?

Yes it is modified!

उत्तर

18

इसके परिणामस्वरूप सी ++ 03 में अपरिभाषित व्यवहार और C++ 11 में अच्छी तरह से परिभाषित व्यवहार होगा।

सी ++ 03: अपरिभाषित Behvaior

सी ++ 03 मानक से, खंड 5 पैरा 4:

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

नोट दूसरा वाक्य: i के पिछले मूल्य केवल संग्रहीत करने के लिए मूल्य निर्धारित करने के लिए इस्तेमाल किया जा सकता। लेकिन यहां यह सरणी सूचकांक निर्धारित करने के लिए भी प्रयोग किया जाता है। इसलिए क्योंकि यह असाइनमेंट i संशोधित करेगा, a[0] = i+1 अच्छी तरह से परिभाषित किया गया है, जबकि a[i] = i+1 नहीं है। ध्यान दें कि असाइनमेंट अनुक्रम बिंदु उत्पन्न नहीं करता है: केवल पूर्ण अभिव्यक्ति (अर्धविराम) का अंत होता है।


सी ++ 11: अच्छी तरह से परिभाषित व्यवहार:

सी ++ 11 अनुक्रम अंक की धारणा से छुटकारा मिला है और इसकी जगह को परिभाषित करता है जो मूल्यांकन जो पहले अनुक्रम कर रहे हैं।

मानक से, खंड 1.9 पैरा 15:

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

असाइनमेंट ऑपरेटर के दोनों ऑपरेटरों को वास्तविक असाइनमेंट से पहले अनुक्रमित किया जाता है। तो a[i] और i+1 दोनों का मूल्यांकन किया जाएगा, और केवल तभी i संशोधित किया जाएगा। परिणाम अच्छी तरह से परिभाषित किया गया है।

+4

+ 1 दोनों सी + +03 और सी ++ 11 उत्तरों। –

3

int i = 0, *a = &i;

घोषणाओं के बीच एक दृश्य मतलब नहीं है, इसलिए कोई यूबी यहाँ। हालांकि ध्यान दें कि इस तरह चर को घोषित/परिभाषित करना एक बुरा विचार है। कोई सामान्य कोडिंग मानक आपको बताएगा कि प्रति पंक्ति एक चर घोषित करें।

a[i] = i;

i, इसलिए कोई यूबी यहाँ या तो किसी भी तरह से नहीं बदला है।

+1

के बारे में क्या 'एक [i] = i + 1;' तो? – Lazer

+2

@Lazer: 'i + 1'' i' या तो –

+0

@Lazer अभी भी नहीं बदलता है, क्योंकि 'i' अभी भी संशोधित नहीं है। –

0

इस मामले में अनिर्धारित व्यवहार केवल तभी होगा जब आप संशोधनों के बीच अनुक्रम बिंदु के बिना समान स्मृति पता संशोधित करें। विशेष रूप से, C99 कल्पना, खंड 6.5/2 राज्यों,

पिछले और अगले अनुक्रम बिंदु के बीच

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

आपके मामले में अनुक्रम बिंदुओं के बीच एक ही स्मृति पता का कोई संशोधन नहीं होता है, इसलिए कोई अपरिभाषित व्यवहार नहीं है।

+2

यहां 'i' को अनुक्रम बिंदु के बिना संशोधित किया जा रहा है (सेमीकॉलन लाइन 2 में एकमात्र अनुक्रम बिंदु है) – Lazer

0

मैं एक बात कहना चाहते हैं: a[i] = iहमेशा अच्छी तरह से परिभाषित व्यवहार के लिए नेतृत्व नहीं है।निर्दिष्ट मामले में व्यवहार अच्छी तरह से परिभाषित किया गया है, प्रारंभिक मान i और a के कारण है। हम i ही है, जो अपरिभाषित व्यवहार का उत्पादन की है कि से एक अलग स्मृति स्थान तक पहुँच रहे हैं

int i = 1, *a = &i; // Line 1, i initialized to anything other than 0 
a[i] = i + 1;   // Line 2, all of a sudden we are in buffer over/underflow 

i के किसी भी अन्य प्रारंभिक मूल्य के लिए:

मुझे विस्तार से बता दें।

+0

असल में जब' एक 'एक पूर्णांक' i' को इंगित करता है, इससे कोई फर्क नहीं पड़ता कि ' मैं हूं, 'एक [i] = i' हमेशा अनिर्धारित व्यवहार होता है (यदि '* (& i + i) = i' यूबी है जो कि, इंटरजे के उत्तर के अनुसार, यह है) –

2

हमें a[i] = i + 1 अभिव्यक्ति को विघटित करने दें?

= -- [] -- a 
    \  \_ i 
    \ 
    \_ + -- i 
     \_ 1 

प्रभावी ढंग से, a[i]&i को संदर्भित करता है लेकिन ध्यान दें कि न तो a[i] और न ही i+1 को संशोधित करता ii केवल तभी संशोधित किया जाता है जब = (असाइनमेंट स्वयं) निष्पादित किया जाता है।इस समारोह के प्रभावी होने से पहले

किसी भी समारोह के ऑपरेंड के बाद से मूल्यांकन किया जा आवश्यकता है, यह वास्तव में के बराबर है:

void assign(int& address, int value) { address = value; } 

assign(a[i], i + 1); 

यह सच है कि = में है कि यह है में निर्मित कुछ हद तक खास है और ऐसा नहीं करता है परिणामस्वरूप फ़ंक्शन कॉल में, अभी भी दोनों ऑपरेटरों का मूल्यांकन वास्तविक असाइनमेंट से पहले अनुक्रमित किया गया है, इसलिए उन्हें पहले i संशोधित होने से पहले मूल्यांकन किया गया है, और a[i] (जो i स्थान पर इंगित करता है) को असाइन किया जा रहा है।

+0

इंटरजे के उत्तर के बारे में क्या कहता है कि पिछले मूल्य को केवल संग्रहीत करने के मूल्य को निर्धारित करने के लिए उपयोग किया जा सकता है? –

+0

इस प्रकार चीजें सी ++ 11 में काम करती हैं, लेकिन सी ++ 03 नहीं (हालांकि कोई उचित सी ++ 03 कंपाइलर शायद इस तरह से चीजों को भी लागू करेगा)। मेरा अद्यतन उत्तर देखें। – interjay

+0

@interjay: आह सही, मैंने कभी भी अनुक्रम बिंदुओं पर बहुत समझदार नहीं दिया है, इसलिए मैंने केवल नवीनतम मानक पर अपना उत्तर आधारित किया है। अच्छा जवाब, पूरी तरह से होने के लिए धन्यवाद। –

0

नहीं, ऐसा नहीं है। पहली पंक्ति एक दृश्य बिंदु (अल्पविराम) है, इसलिए यह अपरिभाषित व्यवहार नहीं है:

int i = 0, *a = &i; 

दूसरी पंक्ति पूरी तरह से सामान्य है।

a[i] = i + 1; 

i + 1 के बाद से एक अस्थायी मूल्य बनाता है, i काम पर केवल एक बार संशोधित हो जाता है,। हालांकि यह अपरिभाषित किया जाएगा व्यवहार:

a[i] = i++; 
संबंधित मुद्दे