2011-10-24 8 views
5
int main(void) 
{ 
    int i = 0; 
    i = ++i % 3; 
    return 0; 
} 

मैं इस तरह यह संकलन:यह क्यों (i = ++ i% 3) चेतावनी उत्पन्न करता है: "अपरिभाषित हो सकता है"?

$ gcc -Wall main.c -o main 
main.c: In function ‘main’: 
main.c:4: warning: operation on ‘i’ may be undefined 

क्यों संकलक कहना i अपरिभाषित किया जा सकता है?

+2

* ऑपरेशन * अपरिभाषित है, न कि मैं स्वयं। अर्थात। यह अपरिभाषित व्यवहार है। ऐसा मत करो –

+0

@ पॉल आर आपको क्यों लगता है कि ऑपरेशन अपरिभाषित है? ++ मैं 1 तक बढ़ता हूं और 3 के साथ मॉड्यूलो ओपेरटर 1 परिणाम के रूप में 1 देता है। क्या वह काम नहीं करता है? – niko

+1

@niko: मेरा उत्तर देखें और http://www.catb.org/jargon/html/N/nasal-demons.html –

उत्तर

4

के रूप में अन्य लोगों ने बताया है, व्यवहार undefined है:

6,5 भाव
...
पिछले और अगले अनुक्रम बिंदु एक वस्तु अपने संग्रहीत मूल्य ज्यादा से ज्यादा संशोधित होगा बीच 2 एक बार अभिव्यक्ति के मूल्यांकन के द्वारा। 72) इसके अलावा, पूर्व मान केवल संग्रहीत करने के मान को निर्धारित करने के लिए पढ़ा जाएगा। 73)
...
72) एक फ़्लोटिंग-पॉइंट स्थिति ध्वज एक वस्तु नहीं है और अभिव्यक्ति के भीतर एक से अधिक बार सेट किया जा सकता है। 73) इस पैरा जबकि (अगले अनुक्रम बिंदु से पहले i दो बार में निहित मूल्य को संशोधित करने के इस मामले में
 
    i = i + 1; 
    a[i] = i; 

अभिव्यक्ति i = ++i % 3 प्रयास की इजाजत दी ऐसी

 
    i = ++i + 1; 
    a[i++] = i; 
के रूप में अपरिभाषित बयान भाव प्रस्तुत हुई है, ; बयान समाप्त करना), एक बार ++i का मूल्यांकन करके, और एक बार बड़ी असाइनमेंट अभिव्यक्ति का मूल्यांकन करके।

अब, यह एक समस्या क्यों होगी? आखिरकार, सी # और जावा इन अभिव्यक्तियों को ठीक से संभाल सकते हैं।

समस्या यह है कि, कुछ अपवादों के साथ, सी गारंटी नहीं देता है कि अभिव्यक्ति में संचालन किसी विशेष क्रम में मूल्यांकन किया जाता है, या अभिव्यक्ति के मूल्यांकन के तुरंत बाद अभिव्यक्ति के साइड इफेक्ट्स लागू किए जाएंगे (सी # और जावा, जो गारंटी देता है)।उदाहरण के लिए, ++i अभिव्यक्ति परिणाम (i + 1) और साइड इफेक्ट (i में संग्रहीत मान को बढ़ाएं); हालांकि, साइड इफेक्ट को तब तक स्थगित कर दिया जा सकता है जब तक कि बड़ी अभिव्यक्ति का मूल्यांकन नहीं किया जाता है। IOW, कार्यों के निम्नलिखित अनुक्रम की अनुमति है:

 
    t0 = i + 1 
    t1 = t0 % 3 
    i = t1 
    i = i + 1 

ओप्सी। हम क्या चाहते थे नहीं।

यह एक जानबूझकर डिजाइन निर्णय था; विचार यह है कि यह संकलक को इष्टतम तरीके से मूल्यांकन को पुन: व्यवस्थित करने की अनुमति देता है (एक मूल्य का लाभ उठाकर जो पहले से ही एक रजिस्टर में है) कहें। नकारात्मकता यह है कि अभिव्यक्तियों के कुछ संयोजनों के अप्रत्याशित परिणाम होंगे।

11

क्योंकि आप i के मान को बिना किसी हस्तक्षेप के sequence point के संशोधित कर रहे हैं। यह undefined behavior है।

6

मानक में, यह अपरिभाषित व्यवहार है क्योंकि i को मध्यवर्ती अनुक्रम बिंदु के बिना दो बार संशोधित किया जाता है।

i = ++i % 3; 

लेकिन यह वास्तव में बिंदु नहीं है। वास्तविक बिंदु यह है: पृथ्वी पर कोई भी ऐसा कोड क्यों लिखता है ?!

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

i = (i+1) % 3; 

जो सी-जैसा-हम जानते हैं-में भी सही है।

+1

+1 "क्यों पृथ्वी पर कोई भी ऐसा कोड लिखता है ?!" –

+0

+1 "क्यों पृथ्वी पर कोई भी ऐसा कोड लिखता है ?!" :) –

संबंधित मुद्दे